众所周知进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中肯定包含一个线程(main线程),一个进程中并且可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
那么什么是线程安全问题?
当N个线程同时操作同一个全局变量或静态变量,做写的操作(修改变量值)时,可能会发生数据冲突问题(资源抢占),也就是线程安全问题。但是做读操作时不会发生数据冲突问题。
举个雷子:
· 创建一个打印方法(打印 当前进程名称&当前耗时任务)
public static void printNum() {
for (int i =0; i <5; i++) {
System.out.println("线程名称:" + Thread.currentThread().getName() +" 耗时打印:" + i);
}
}
·创建两个线程
public static class MyThread1 extends Thread {
@Override
public void run() {
super.run();
printNum();
}
}
public static class MyThread2 extends Thread {
@Override
public void run() {
super.run();
printNum();
}
}
·在main函数中开启两个线程
public static void main(String[] agrs) {
MyThread1 myThread1 = new MyThread1();
myThread1.start();
MyThread2 myThread2 = new MyThread2();
myThread2.start();
}
·看下输出
线程名称:Thread-0 耗时打印:0
线程名称:Thread-0 耗时打印:1
线程名称:Thread-0 耗时打印:2
线程名称:Thread-1 耗时打印:0
线程名称:Thread-0 耗时打印:3
线程名称:Thread-1 耗时打印:1
线程名称:Thread-0 耗时打印:4
线程名称:Thread-1 耗时打印:2
线程名称:Thread-1 耗时打印:3
线程名称:Thread-1 耗时打印:4
哎呀我去~交叉打印,我们来看下是为啥子:
原来线程的执行是CPU随机执行的,比如我们开启N个线程,这N个线程并不是同时执行的,而是CPU快速的在这N个线程之间切换执行,所以才会出现上面的情况,那么我们如何来解决这个问题呢?
在JDK1.5之前是通过关键字 synchronized 来进行代码同步的,也就是说当线程A执行该方法时就宣布了现在这个代码是我的了,如果 此时线程B想来执行这段代码,线程A说没门,让我干完再说;
·将printNum方法增加synchronized关键字
public static synchronized void printNum() {
for (int i = 0; i < 5; i++) {
System.out.println("线程名称:" + Thread.currentThread().getName() + " 耗时打印:" + i);
}
}
·看效果
线程名称:Thread-0 耗时打印:0
线程名称:Thread-0 耗时打印:1
线程名称:Thread-0 耗时打印:2
线程名称:Thread-0 耗时打印:3
线程名称:Thread-0 耗时打印:4
线程名称:Thread-1 耗时打印:0
线程名称:Thread-1 耗时打印:1
线程名称:Thread-1 耗时打印:2
线程名称:Thread-1 耗时打印:3
线程名称:Thread-1 耗时打印:4
在JDK1.5之后java加了个Lock锁,也是解决这个问题的,如果说synchronized是隐式的,那么Lock就是显示的,需要开发者进行上锁及解锁操作
看骚操作:
static Lock lock = new ReentrantLock();
public static void printNum() {
lock.lock();
try {
for (int i = 0; i < 5; i++) {
System.out.println("线程名称:" + Thread.currentThread().getName() + " 耗时打印:" + i);
}
} finally {
lock.unlock();
}
}
首先通过ReentrantLock创建了一个Lock,在代码前加上Lock.lock方法,那么unlock要放在finally中呢,原因是假如线程A执行代码出现异常unlock可能就不能被执行,也就是无法进行解锁,那么线程B就无法拿到锁,就无法进行代码执行了
看效果:
线程名称:Thread-0 耗时打印:0
线程名称:Thread-0 耗时打印:1
线程名称:Thread-0 耗时打印:2
线程名称:Thread-0 耗时打印:3
线程名称:Thread-0 耗时打印:4
线程名称:Thread-1 耗时打印:0
线程名称:Thread-1 耗时打印:1
线程名称:Thread-1 耗时打印:2
线程名称:Thread-1 耗时打印:3
线程名称:Thread-1 耗时打印:4
两种线程同步(抢占资源)的解决方式:
1、方法或代码块增加synchronized 关键字
2、方法前lock 方法后 unlock
网友评论