【java】【多线程】线程安全与线程非安全【1】

线程安全与线程非安全,怎样区分呢?


其实,当线程访问同一资源时,如同一个对象的同一个变量,会存在多个线程对同一资源的竞争访问,也就存在线程非安全。所以说,非安全指的是:多个线程访问同一个资源,可能会访问到非想要的资源。如线程一改写了变量a,而线程二此时又来访问变量a,则线程二得到的是修改后的变量a,而不是修改前的变量a。这样,就存在了数据的非安全访问,称之为线程非安全。这也可以称为数据的脏读。


反之,如果两个线程不会访问同样的资源,则不会存在上述问题,所以,称之为线程安全。


那是不是只要;两个线程访问同一对象的同一资源就是线程不安全的呢?

这也不是。如果访问的是同一个方法,而该方法有没有访问类的其他属性,则该方法的访问不存在线程安全问题。即:方法内部的局部变量是线程安全的。


代码如下:

package com.cmm.thread1;

public class ThreadSafe {
	
	public void add(int a) throws InterruptedException{
		int num = 0;
		if(a == 100){
			num = 100;
			Thread.sleep(1000);
			System.out.println("num = " + num);
		}else{
			num = 200;
			System.out.println("num = " + num);
		}
	}
}
package com.cmm.thread1;

public class ThreadA extends Thread{
	private ThreadSafe safe;
	public ThreadA(ThreadSafe safe) {
		this.safe = safe;
	}
	@Override
	public void run() {
		super.run();
		try {
			this.safe.add(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
package com.cmm.thread1;

public class ThreadB extends Thread{
	private ThreadSafe safe;
	public ThreadB(ThreadSafe safe) {
		this.safe = safe;
	}
	@Override
	public void run() {
		super.run();
		try {
			this.safe.add(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}

测试代码如下:

package com.cmm.thread1;

public class Main {
	public static void main(String[] args) {
		ThreadSafe safe = new ThreadSafe();
		
		ThreadA threadA = new ThreadA(safe);
		
		ThreadB threadB = new ThreadB(safe);
		
		threadA.start();
		threadB.start();
		
	}
}

多次测试结果为:

num = 200
num = 100


可以看出,多个线程访问同一方法的局部变量是线程安全的。


但是,如果是类的属性,则存在线程不安全的问题。

修改代码如下:

package com.cmm.thread1;

public class ThreadSafe {
	private int num = 0;
	public void add(int a) throws InterruptedException{
		
		if(a == 100){
			num = 100;
			Thread.sleep(1000);
			System.out.println("num = " + num);
		}else{
			num = 200;
			System.out.println("num = " + num);
		}
	}
}


测试结果如下:

num = 200
num = 200


可以看出,出现的数据脏读。


当多线程访问同一资源时,就会出现脏读问题。所以,这个时候,需要用一定的手段,来使得同一时刻,只有一个线程可以对共享资源进行访问。访问分两种,只读,读写。所以又有不同的处理。


后面,会详细介绍线程同步问题。


在这里先总结一句话:线程同步问题,就是为了解决多个线程对共享数据的同时访问问题,访问又分为只读与读写两种,所以,线程同步,需要分场景做不同的讨论处理。


你可能感兴趣的:(Java多线程)