线程2-线程同步

1、线程安全问题原因?
由于一个线程在操作一个共享数据时,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在安全问题
2、如何解决线程安全问题?
一个线程操作完共享数据以后,其他线程才可以操作共享数据
3、java使用线程同步机制实现,线程安全
方式一:同步代码块
synchronized(Object obj){ //可以是任何一个对象,对象不能为线程私有
//操作共享数据的代码块
}
(1)共享数据
(2)同步监视器(上面的obj参数),对象锁,由一个对象充当,哪个类获取到对象锁,就执行同步代码
方式二:
(1)将需要同步的代码块,放到一个方法,对方法加同步
(2)同步方法,对象锁默认this

4、同步要注意的:

(1)synchronized修饰非静态方法,里面是当前类的对象
(2)synchronized静态方法的锁是当前类的字节码文件对象 类名.class
(3)多个线程必须用同一把对象锁,否则锁无效,非static锁定实列,static 锁定类

5、例1,继承方式实现多窗口卖票,非线程安全

package com.thread.test;



/**
 * 
 * 继承方式:模拟火车站售票
 *存在线程安全问题
 */
class Window extends Thread{
    static int ticket = 100;
    static int k = 0 ;
    @Override
    public void run(){
        while(true){
            if(ticket > 0){
                System.out.println(Thread.currentThread().getName()+"售票号码:"+ticket);
                k++;
                ticket --;
            }else{
                System.out.println("All "+k);
                break;
            }
        }
    }
}
public class TestWindowExtends{
    
    public static void main(String[] args) {
        Window w1 = new Window();
        Window w2 = new Window();
        Window w3 = new Window();
        
        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");
        
        w1.start();
        w2.start();
        w3.start();
    }
}

例2,继承方式多窗口卖票,线程安全

package com.thread.test;



/**
 * 
 * 继承方式:模拟火车站售票
 *存在线程安全问题
 */
class Window3 extends Thread{
    static int ticket = 100;
    static int k = 0 ;
    static Object obj = new Object();
    @Override
    public void run(){
        
            while(true){
                synchronized(obj){//注意和实现implements方法对象锁的不同
                if(ticket > 0){
                    System.out.println(Thread.currentThread().getName()+"售票号码:"+ticket);
                    k++;
                    ticket --;
                }else{
                    System.out.println("All "+k);
                    break;
                }
            }
        }
    }
}
public class TestWindowExtends同步代码块{
    
    public static void main(String[] args) {
        Window w1 = new Window();
        Window w2 = new Window();
        Window w3 = new Window();
        
        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");
        
        w1.start();
        w2.start();
        w3.start();
    }
}

例3、实现Runnable接口实现多窗口卖票,线程安全,同步代码块

package com.thread.test;

/**
 *    1、线程安全问题原因?
 *        由于一个线程在操作一个共享数据时,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在安全问题 
 *    2、如何解决线程安全问题?
 *        一个线程操作完共享数据以后,其他线程才可以操作共享数据
 *    3、java使用线程同步机制实现,线程安全
 *        方式一:同步代码块
 *            synchronized(Object obj){ //可以是任何一个对象,对象不能为线程私有
 *                //操作共享数据的代码块
 *            }
 *            (1)共享数据
 *            (2)同步监视器(上面的obj参数),对象锁,由一个对象充当,哪个类获取到对象锁,就执行同步代码
 *        方式二:
 *            (1)将需要同步的代码块,放到一个方法,对方法加同步
 *            (2)同步方法,对象锁默认this
 */
class Window2 implements Runnable{
    int ticket = 100;
    int count = 0;
    @Override
    public void run() {
        //this表示当前对象,因为,在下面的main方法中,只创建了一次Windows2对象,所以,this代表的当前对象是三个线程共享的,对象锁唯一。所以可以用this
        //而在继承方式中,对象锁不能用this,因为,在main方法中Windows对象被创建了3次,this对应三个对象,对象不唯一,所以不能用this
        //多个线程用同一把对象锁
        
            while(true){
                synchronized(this){//不要写到while外面,while外面,就会只有线程1执行代码
                if(ticket >0){
                    System.out.println("线程"+Thread.currentThread().getName()+"出售票号:"+ticket);
                    ticket --;
                    count ++;
                }else{
                    System.out.println("Aall "+count);
                    break;
                }
            }
            
        }
        
        
    }
    
}

public class TestWindowImplements同步代码块 {
    public static void main(String[] args) {
        //继承方式只需创建一个Window对象
        Window1 window = new Window1();
        
        //三个线程操作同一个对象
        Thread t1 = new Thread(window);
        t1.setName("t1");
        Thread t2 = new Thread(window);
        t2.setName("t2");
        Thread t3 = new Thread(window);
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

例4、实现Runnable接口实现多窗口卖票,线程安全,同步方法

package com.thread.test;

class Window4 implements Runnable{
    int ticket = 100;
    int count = 0;
    @Override
    public void run() {
        while(true){
            sell();
        }
        
    }
    
    //对象锁默认this
    public synchronized void sell(){
        if(ticket >0){
            System.out.println("线程"+Thread.currentThread().getName()+"出售票号:"+ticket);
            ticket --;
            count ++;
        }
    }
    
}

public class TestWindowImplements同步方法 {
    public static void main(String[] args) {
        //继承方式只需创建一个Window对象
        Window4 window = new Window4();
        
        //三个线程操作同一个对象
        //由于三个线程会同时操作ticket这一变量,所以会出现同步问题,所以要加同步
        Thread t1 = new Thread(window);
        t1.setName("t1");
        Thread t2 = new Thread(window);
        t2.setName("t2");
        Thread t3 = new Thread(window);
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

需要注意的事项都写在注释里

原文地址:https://www.cnblogs.com/fubaizhaizhuren/p/5066531.html