如何处理线程并发时产生的线程安全问题(Runnable和Thread)

来源:互联网 发布:淘宝网9.9包邮 编辑:程序博客网 时间:2024/05/22 13:33

在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runnable接口。多线程执行没有一个确定的顺序,并不是先启动线程一定先执行,当前一刻,谁抢占了cpu资源,谁就执行
一.实现runnable接口
位于同一个Thread对象里,t1,t2两条线程的run()方法,其实是一个run(),都在调用静态方法区的sum,将会导致线程安全问题
这里写图片描述

public  class Class2 {    public static void main(String args[])throws Exception{        class3 r=new class3();        Thread t1=new Thread(r);        Thread t2=new Thread(r);        t1.start();        t1.join();//如果join()位于此处会引发线程安全问题,结果混乱        t2.start();        t2.join();        System.out.println(class3.sum);    }}class class3 implements Runnable{    public static int sum=0;    public void add(){        for(int i=0;i<5000;i++){            sum=sum+1;        }    }    public void run(){        add();    }}//结果为10000。当t1.start()之后接t1.join()之后结果为10000。同一线程不能启动多次

同步锁
加了同步锁的方法或代码段,在同一时刻,只允许获得当前锁对象的一条线程执行,执行完成后,释放锁对象。
1.动态方法同步锁,锁对象为当前实例对象

public  class Class2 {    public static void main(String args[])throws Exception{        class3 r=new class3();        Thread t1=new Thread(r);        Thread t2=new Thread(r);        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println(class3.sum);    }}class class3 implements Runnable{    public static int sum=0;    public synchronized void add(){//动态方法同步锁        for(int i=0;i<5000;i++){            sum=sum+1;        }    }    public void run(){        add();    }}//结果为10000,解决了线程安全问题

2静态方法同步锁,锁对象为当前类

public  class Class2 {    public static void main(String args[])throws Exception{        class3 r=new class3();        Thread t1=new Thread(r);        Thread t2=new Thread(r);        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println(class3.sum);    }}class class3 implements Runnable{    public static int sum=0;    public static synchronized void add(){//静态方法同步锁        for(int i=0;i<5000;i++){            sum=sum+1;        }    }    public void run(){        add();    }}//结果为10000,解决了线程安全问题

3代码段同步锁,自定义锁对象(动态/静态)

public  class Class2 {    public static void main(String args[])throws Exception{        class3 r=new class3();        Thread t1=new Thread(r);        Thread t2=new Thread(r);        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println(class3.sum);    }   }class class3 implements Runnable{    public static int sum=0;    public Object lock=new Object();    public void add(){        synchronized(lock){            for(int i=0;i<5000;i++){                sum=sum+1;            }        }    }    public void run(){        add();    }}//结果为10000,解决了线程安全问题

二,Thread类
join() 方法,它能够使调用该方法的线程在此之前执行完毕。
如果不使用t.join()方法,主线程main方法的System.out.println(a);语句将抢先执行。当主线程 main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被 改变的值0 。
这里写图片描述
由上图可知,有t1,t2两个不同的对象,他们各自有各自的run()方法,如果只是锁定run(synchronized add();),仍然会导致线程安全问题

public class Mydemo {    public static void main(String[] args)throws Exception{        Mydemo1 r=new Mydemo1();        r.start();        System.out.println(Mydemo1.sum);    }}class Mydemo1 extends Thread{    public  static int sum=0;    public  void add(){        for(int i=0;i<5000;i++){            sum=sum+1;                      }    }    public void run(){        add();    }}//输出的结果为0,由此可知join()方法的重要性

有join()方法

public class Mydemo {    public static void main(String[] args)throws Exception{        Mydemo1 r=new Mydemo1();        Mydemo1 r1=new Mydemo1();        r.start();        r.join();        r1.start();        r1.join();        System.out.println(Mydemo1.sum);    }}class Mydemo1 extends Thread{    public  static int sum=0;    public    void add(){        for(int i=0;i<5000;i++){            sum=sum+1;                      }    }    public void run(){        add();    }}//结果为10000.当r.start()后不接r.join()时出现不确定数字

动态同步锁

public class Mydemo {    public static void main(String[] args)throws Exception{        Mydemo1 r=new Mydemo1();        Mydemo1 r1=new Mydemo1();        r.start();        r1.start();        r.join();        r1.join();        System.out.println(Mydemo1.sum);    }}class Mydemo1 extends Thread{    public  static int sum=0;    public  synchronized  void add(){        for(int i=0;i<5000;i++){            sum=sum+1;                      }    }    public void run(){        add();    }}//结果为不确定数字,因为r,r1为不同对象,锁住的是各自的add()方法,使用的还是同一个静态区的变量,仍会出现并发线程安全问题

静态同步锁

public class Mydemo {    public static void main(String[] args)throws Exception{        Mydemo1 r=new Mydemo1();        Mydemo1 r1=new Mydemo1();        r.start();        r1.start();        r.join();        r1.join();        System.out.println(Mydemo1.sum);    }}class Mydemo1 extends Thread{    public  static int sum=0;    public static  synchronized  void add(){        for(int i=0;i<5000;i++){            sum=sum+1;                      }    }    public void run(){        add();    }}//加上static 之后使add()方法位于静态区,公共的大家都可以调用,加上静态锁后谁先抢占后先执行后面一个再执行
原创粉丝点击