java thread study

举报
yd_57386892 发表于 2021/03/29 04:21:24 2021/03/29
【摘要】 0. 用runnable创建线程具有面向对象的思想。 1. quartz  定时器开源库。 3.  多线程间的互斥:   (1)多线程间的互斥,用synchronized关键字,两个线程用互斥锁必须用同一个对象才能实现互斥。   (2) 两个非静态函数前加synchronized关键字,它们的公用锁是this,就是当前对象实例。 (...


0. 用runnable创建线程具有面向对象的思想。
1. quartz  定时器开源库。
3.  多线程间的互斥:
 
(1)多线程间的互斥,用synchronized关键字,两个线程用互斥锁必须用同一个对象才能实现互斥。
 
(2) 两个非静态函数前加synchronized关键字,它们的公用锁是this,就是当前对象实例。

(3)静态函数前加synchronized关键字,它用的锁对象是.class字节码,这个时u候与要将非静态函数的synchronized(this)锁改为synchronized(MyClass.class),即字节码锁
 两个函数这才使用了同一个锁:类的字节码对象,从而才实现了互斥。
 
 例如:2 个线程调用同一个Output对象的output1(“gaoxiaowei”)和output2(“lichao”)两个函数, 会出现打印gaoxiaowei  lichao    gaolichao xiaowei这样第二行错乱的问题。
 在这里临界资源是输出屏幕? 我如果让一个线程调用ouput1对象的output,然后另一个线程调用output2对象的output,在不加锁的情况下会错乱吗?
 
 答:
 
 (1)如果output函数的同步锁是object.class字节码时,就不会错乱,因为两个线程 的两个output对象在执行output1函数时,用的是同一把锁object.class;
 
 (2)如果output的同步锁是this,那么会错乱,因为两个线程分别持有2个对象output1与ouput2,是两个this,因此output函数上的synchronized用的o是2把不同的
 this锁,各自执行各自的,都可以在这个临界资源——屏幕上输出。如第一个线程正在输出gaolichao结果第二个线程打印lichao插到了第一个线程的输出中间。

 (3)是的,这里的临界资源就是显示器,而不是公用的output类对象,因为即使2个线程分别创建一个output对象:output1与output2,如果锁不是同一个的话,
 也会出现打印错误。除非有2个显示器,一个线程往显示器1输出,另一个线程往显示器2输出,这才不冲突,因为2个已经是1对1,不存在公用竞争问题。
 
 
 
 4.多线程间的同步
 wait 和 notify
 现在有这么一个题目:子线程执行10次,然后主线程再执行100次,接着轮到子线程再执行10次,然后主线程又执行100次,两个线程这样轮流执行,总共50回。
 
step1: 定义一个业务类,封装两个函数:(1)打印10次sub  (2)打印100次main;
step2: 定义1个子线程,外层for循环都是50次,然后每循环1次调用业务类中的 函数(1u)打印10次sub
        主线程,外层for循环都是50次,然后每循环1次调用业务类中的 函数(2)打印50次main
    
step3:先解决互斥问题:就是在打印sub的10次循环时,不能穿插打印main;同理打印main的100次的时候,不能穿插子线程的sub打印。这个好办,给业务类的
函数1和函数2前加synchronized关键字,这样就实现了打印sub的10次时,由于正在占用同一个对象锁this,因此它不会被函数(2)打断。

step4:解决同步配合问题,先子线程打印10次,子线程打印完了,然后执行notify,唤醒主线程去打印100次(主线程刚开始会调用waite),然后主线程打印完100次,再去唤醒子线程去打印。
       
 注意synchronized括起来的对象要与调用wait,notify是同一个对象,并且这个object.notify,object.wait中的object要被括在synchronized里,否则会报错:java.lang.IllegalMonitorStateException
 实例代码如下:
 

import java.util.concurrent.atomic.AtomicInteger;

public class TraditionalThreadCommunication {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        final Business business = new Business();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for(int i=1;i<=50;i++){
                            business.sub(i);
                        }
                    }
                }
        ).start();
        
        for(int i=1;i<=50;i++){
            business.main(i);
        }
        
    }

}

  class Business {
      private boolean bShouldSub = true;
      
      Object obj;
      public Business()
      {
          obj = new Object();
      }

      public synchronized void sub(int i){
          
          synchronized(obj)
          {
              while(!bShouldSub){
                  try {
                      obj.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
              }
                for(int j=1;j<=10;j++){
                    System.out.println("sub thread sequence of " + j + ",loop of " + i);
                }
              bShouldSub = false;
              obj.notify();
          }
    
      }
      
      public  void main(int i){
          
          synchronized(obj)
          {
              
                  while(bShouldSub){
                      try {
                          obj.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                  }
                for(int j=1;j<=100;j++){
                    System.out.println("main thread sequence of " + j + ",loop of " + i);
                }
                bShouldSub = true;
                obj.notify();
          }
        
      }
  }
或者:
public class TraditionalThreadCommunication {

    public static void main(String[] args) {
        
        final Business business = new Business();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for(int i=1;i<=50;i++){
                            business.sub(i);
                        }
                    }
                }
        ).start();
        
        for(int i=1;i<=50;i++){
            business.main(i);
        }    
    }
}
  class Business {
      private boolean bShouldSub = true;
     
      public synchronized void sub(int i){
          
              while(!bShouldSub){
                  try {
                      this.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
              }
                for(int j=1;j<=10;j++){
                    System.out.println("sub thread sequence of " + j + ",loop of " + i);
                }
              bShouldSub = false;
              this.notify();
      }
     
      public synchronized void main(int i){
                  while(bShouldSub){
                      try {
                          this.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                  }
                for(int j=1;j<=100;j++){
                    System.out.println("main thread sequence of " + j + ",loop of " + i);
                }
                bShouldSub = true;
                this.notify();
      }
  }
  
  
  5. 多线程间的互斥,用synchronized关键字包裹的函数内部如果生成了 一个死循环线程,那么这个函数的锁子能释放吗?
  答:能。因为synchronized是用于当前线程同步的;还有就是生成的那个线程并不会阻塞当前函数的执行,函数执行完成后自然会释放synchronized锁。

 

6.当一个线程处于sleep时,Thread.isAlive函数返回false

 

7.线程范围内的共享变量

同一个变量,在线程间共享,例如下面的变量x,线程内独立,表示线程内是一份独立的数据。

(1)可以用hashmap.put(Thread.name, data);  来实现

(2)ThreadLocal来实现

下面的x,是演示单个共享变量

 

package cn.itcast.heima2;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadLocalTest {

    private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
    private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();
    public static void main(String[] args) {
        for(int i=0;i<2;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    int data = new Random().nextInt();
                    System.out.println(Thread.currentThread().getName() 
                            + " has put data :" + data);
                    x.set(data);
/*                    MyThreadScopeData myData = new MyThreadScopeData();
                    myData.setName("name" + data);
                    myData.setAge(data);
                    myThreadScopeData.set(myData);*/
                    MyThreadScopeData.getThreadInstance().setName("name" + data);
                    MyThreadScopeData.getThreadInstance().setAge(data);
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }
    
    static class A{
        public void get(){
            int data = x.get();
            System.out.println("A from " + Thread.currentThread().getName() 
                    + " get data :" + data);
/*            MyThreadScopeData myData = myThreadScopeData.get();;
            System.out.println("A from " + Thread.currentThread().getName() 
                    + " getMyData: " + myData.getName() + "," +
                    myData.getAge());*/
            MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
            System.out.println("A from " + Thread.currentThread().getName() 
                    + " getMyData: " + myData.getName() + "," +
                    myData.getAge());
        }
    }
    
    static class B{
        public void get(){
            int data = x.get();            
            System.out.println("B from " + Thread.currentThread().getName() 
                    + " get data :" + data);
            MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
            System.out.println("B from " + Thread.currentThread().getName() 
                    + " getMyData: " + myData.getName() + "," +
                    myData.getAge());            
        }        
    }
}

class MyThreadScopeData{
    private MyThreadScopeData(){}
    public static /*synchronized*/ MyThreadScopeData getThreadInstance(){
        MyThreadScopeData instance = map.get();
        if(instance == null){
            instance = new MyThreadScopeData();
            map.set(instance);
        }
        return instance;
    }
    //private static MyThreadScopeData instance = null;//new MyThreadScopeData();
    private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
    
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
 

8.多个线程间共享数据的探讨

方法1:new Thread(new Runnable()

          {

              data1.decrement();

          }

        )

方法2:        new Thread(new MyRunnable1(data2)).start();
        new Thread(new MyRunnable2(data2)).start();

将数据data2作为构造函数参数传到Runnable里去。

方法3:

定义2个Runnable内部类,访问外部类的成员变量j

 

方法1和方法2的代码:

package cn.itcast.heima2;

public class MultiThreadShareData {

    private static ShareData1 data1 = new ShareData1();
    
    public static void main(String[] args) {
        ShareData1 data2 = new ShareData1();
        new Thread(new MyRunnable1(data2)).start();
        new Thread(new MyRunnable2(data2)).start();
        
        final ShareData1 data1 = new ShareData1();
        new Thread(new Runnable(){
            @Override
            public void run() {
                data1.decrement();
                
            }
        }).start();
        new Thread(new Runnable(){
            @Override
            public void run() {
                data1.increment();
                
            }
        }).start();

    }

}
    
    class MyRunnable1 implements Runnable{
        private ShareData1 data1;
        public MyRunnable1(ShareData1 data1){
            this.data1 = data1;
        }
        public void run() {
            data1.decrement();
            
        }
    }
    
    class MyRunnable2 implements Runnable{
        private ShareData1 data1;
        public MyRunnable2(ShareData1 data1){
            this.data1 = data1;
        }
        public void run() {
            data1.increment();
        }
    }

    class ShareData1 /*implements Runnable*/{
/*        private int count = 100;
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                count--;
            }
        }*/
        
        
        private int j = 0;
        public synchronized void increment(){
            j++;
        }
        
        public synchronized void decrement(){
            j--;
        }
    }

方法3的代码:

外部类:

        private int j = 0;
        public synchronized void increment(){
            j++;
        }
        
        public synchronized void decrement(){
            j--;
        }

内部类:

MyIncrementRunnable()

{

increment();  //内部类调用外部类成员,还是以外部类对象为同步锁

}

 

MyDecrementRunnable()

{

decrement();

}

文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/100825669

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。