1 线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
线程不安全代码示例:
public class MyRunnable implements Runnable {
// 总共50张票
int ticket = 50;
@Override
public void run() {
// 模拟卖票
while (true) {
if (ticket>0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" is sailing.... "+ticket--);
}
}
}
}
public static void main(String[] args) {
MyRunnable myRunnable=new MyRunnable();
Thread t1=new Thread(myRunnable,"window 1");
Thread t2=new Thread(myRunnable,"window 2");
Thread t3=new Thread(myRunnable,"window 3");
t1.start();
t2.start();
t3.start();
}
// 运行结果:
window 3 is sailing.... 5
window 1 is sailing.... 4
window 2 is sailing.... 3
window 3 is sailing.... 2
window 2 is sailing.... 1
window 1 is sailing.... 0 // 出现问题
window 3 is sailing.... -1 // 出现问题
2 线程同步
线程同步有两种方式:
- 同步代码块
- 同步方法
2.1 同步代码块
格式:
synchronized(锁对象){
可能会产生线程安全问题的代码
}
注意: 同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。
示例:
public class MyRunnable implements Runnable {
// 总共500张票
int ticket = 500;
// 定义锁对象
Object lock = new Object();
@Override
public void run() {
// 模拟卖票
while (true) {
// 同步代码块
synchronized (lock) {
if (ticket > 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is sailing.... " + ticket--);
}
}
}
}
}
2.2 同步方法
格式:
public synchronized void method(){
可能会产生线程安全问题的代码
}
示例:
public class MyRunnable implements Runnable {
// 总共50张票
int ticket = 500;
// 同步方法,锁对象this
public synchronized void method() {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is sailing.... " + ticket--);
}
}
@Override
public void run() {
// 模拟卖票
while (true) {
// 同步方法
method();
}
}
}
3 死锁
同步锁使用的弊端: 当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。
4 Lock接口
示例:
public class MyRunnable implements Runnable {
// 总共500张票
int ticket = 500;
// 1 创建lock锁对象
Lock ck=new ReentrantLock();
@Override
public void run() {
// 模拟卖票
while (true) {
// 2 获取锁
ck.lock();
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is sailing.... " + ticket--);
}
// 3 释放锁
ck.unlock();
}
}
}