Java多线程理解(线程安全)

我们在使用Java多线程时,一定需要考虑到共享,线程安全的相关内容。以下通过几个例子帮助大家来理解多线程时如何运行的,后续通过一篇文章详述解决办法:synchronized。

场景1:

package com.test;
public class Test1 {  
	public static void main(String[] args) {  
        B b = new B();  
        Thread th1 = new Thread(b, "one"); //2个线程都对应同一个target对象b (单例模式)非线程安全  
        Thread th2 = new Thread(b, "two");  
        th1.start();  
        th2.start();  
    }  
}  

class B implements Runnable{  
     public int x=0; // B类的实例变量  
    public void run() {  
        for(int i=0;i<5;i++){  
              x++;  
            System.out.println("[当前线程]----------"+Thread.currentThread().getName()+"====="+"实例变量的值----x="+x);  
        }  
    }  
}  

第一次运行结果:

[当前线程]----------one=====实例变量的值----x=1
[当前线程]----------two=====实例变量的值----x=2
[当前线程]----------two=====实例变量的值----x=3
[当前线程]----------two=====实例变量的值----x=4
[当前线程]----------two=====实例变量的值----x=5
[当前线程]----------two=====实例变量的值----x=6
[当前线程]----------one=====实例变量的值----x=7
[当前线程]----------one=====实例变量的值----x=8
[当前线程]----------one=====实例变量的值----x=9
[当前线程]----------one=====实例变量的值----x=10

分析总结:我们在这里看到运行结果从1-10,线程th1和线程th2各自增加,此时两个线程公用一个对象B,所以也就共用x变量。且运行的是run函数里面的程序。

场景2:解决X变量被共用问题:

方法1:将int x=0;放入到run()函数中,此时,每个线程,都是从x=0开始执行;

方法2:创建多个B类的实例,比如b,b1,各自创建对应的线程进行处理,此时,两个线程互不干涉,代码如下

package com.test;

public class Test1 {
	public static void main(String[] args) {
		
		B b = new B();
		B b1 = new B();
		Thread th1 = new Thread(b, "one"); //2个线程都对应同一个target对象b (单例模式)非线程安全
		Thread th2 = new Thread(b1, "two");
		th1.start();
		th2.start();
	}
}

class B implements Runnable{
	 // B类的实例变量
	public void run() {
		int x=0;
		for(int i=0;i<5;i++){
			  x++;
			System.out.println("[当前线程]----------"+Thread.currentThread().getName()+"====="+"实例变量的值----x="+x);
		}
	}
	
	
}


运行结果如下:

[当前线程]----------two=====实例变量的值----x=1
[当前线程]----------one=====实例变量的值----x=1
[当前线程]----------one=====实例变量的值----x=2
[当前线程]----------one=====实例变量的值----x=3
[当前线程]----------two=====实例变量的值----x=2
[当前线程]----------one=====实例变量的值----x=4
[当前线程]----------one=====实例变量的值----x=5
[当前线程]----------two=====实例变量的值----x=3
[当前线程]----------two=====实例变量的值----x=4
[当前线程]----------two=====实例变量的值----x=5

场景3:我们计划共同使用X,但是线程之间的运行需要先得到的运行结束后,后续的进程才能获得使用权,此时我们需要使用synchronized关键字来处理了代码如下。

package com.test;
public class Test1 {  
	public static void main(String[] args) {  
        B b = new B();  
        Thread th1 = new Thread(b, "one"); //2个线程都对应同一个target对象b (单例模式)非线程安全  
        Thread th2 = new Thread(b, "two");  
        th1.start();  
        th2.start();  
    }  
}  

class B implements Runnable{  
    int x=0; // B类的实例变量  

    public void run() { 
    	synchronized(this){
        for(int i=0;i<5;i++){  
              x++;  
            System.out.println("[当前线程]----------"+Thread.currentThread().getName()+"====="+"实例变量的值----x="+x);  
        }  
    }  
    }
} 

运行结果如下

[当前线程]----------one=====实例变量的值----x=1
[当前线程]----------one=====实例变量的值----x=2
[当前线程]----------one=====实例变量的值----x=3
[当前线程]----------one=====实例变量的值----x=4
[当前线程]----------one=====实例变量的值----x=5
[当前线程]----------two=====实例变量的值----x=6
[当前线程]----------two=====实例变量的值----x=7
[当前线程]----------two=====实例变量的值----x=8
[当前线程]----------two=====实例变量的值----x=9
[当前线程]----------two=====实例变量的值----x=10

分析总结:我们在这里看到运行结果从1-10,但是运行过程中,是线程th1结束后,再开始th2。因为加了synchronzied,实现了同步,并且该对象锁对应的对象只有一个,那就是b,所以当第一个线程锁住了b,而第二个线程里面也是通过b去访问run()方法,所以必须等第一个线程执行完对象的方法时才能获得对象锁。

下一篇文章我们详细分析synchronized(同步)的概念。

先来一个总结:

1. java中的每个对象都有一个锁,当访问某个对象的synchronized方法时,表示将该对象上锁,此时其他任何线程都无法在去访问该syncronized 方法了,直到之前的那个线程执行方法完毕后,其他线程才有可能去访问该synchronized方法。 

2.如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到某个synchronzed方法,那么在该方法没有执行完毕前,其他线程无法访问该对象的任何synchronzied 方法的,但可以访问非synchronzied方法。 

3.如果synchronized方法是static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchuronized方法所在对象的对应的Class对象, 
因为java中无论一个类有多少个对象,这些对象会对应唯一一个Class 对象,因此当线程分别访问同一个类的两个对象的static,synchronized方法时,他们的执行也是按顺序来的,也就是说一个线程先执行,一个线程后执行。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值