多线程的安全问题:
当多个线程访问共享数据时,可能会出现线程安全问题。
产生问题的原因:
1.线程任务中有处理到共享的数据;
2.线程任务中有多条对共享数据的操作。
一个线程在操作共享数据的过程中,其他线程参与了运算,造成了数据的错误。
如何解决多线程的安全问题:
只要保证多条操作共享数据的代码在某一时间段,被一条线程所执行,在期间不允许其他线程参与运算。
如何保证?
1.使用同步代码块
synchronized(锁){
需要被同步的代码
}
注意:锁可以是任意对象,锁是唯一的。
同步在目前情况下保证了一次只能有一个线程在执行,其他的线程进不来。
同步代码块规则:
当线程进入同步代码块的时候,先看一下有没有锁,如果有锁,就进入同步代码块中执行代码。进去的同时会获取这把锁,当代码执行完毕,出同步代码块时,将这把锁释放。如果没锁,线程在同步代码块前等待,有锁才进入。
好处:解决了多线程的安全问题。
弊端:降低了效率。
2.同步方法(作用和同步代码块相同)
也使用synchronized关键字,关键字声明在方法上。
3.静态方法(和上面两种方法作用相同)
静态方法同样有锁,不过和成员方法不同,由于静态方法加载的时候还没有对象,所以静态方法的锁用的是该类的字节码文件对象:类名.class。
Lock接口
JDK1.5后出现。
他比synchronized有更多的操作。
lock();获取锁
unlock();释放锁
为了保证锁一定会被释放,可以使用finally。
线程的死锁
前提:
1.必须要有同步锁的嵌套
2.锁对象要唯一(两把锁都要保证唯一)
public class Test {
public static void main(String[] args) {
DeadLock deadLock = new DeadLock();
Thread t1 = new Thread(deadLock);
Thread t2 = new Thread(deadLock);
t1.start();
t2.start();
}
}
// 实现Runnable接口
class DeadLock implements Runnable{
// 标记,控制线程进程进入不同方法
private boolean flag = false;
@Override
public void run() {
// 防止线程正常运行,多试几次,直到出现死锁
while(true) {
if (!flag) {
synchronized(LockA.LOCK_A) {
System.out.println("我是if的A锁");
synchronized (LockB.LOCK_B) {
System.out.println("我是if的B锁");
}
}
} else {
synchronized(LockB.LOCK_B) {
System.out.println("我是else的B锁");
synchronized (LockA.LOCK_A) {
System.out.println("我是else的A锁");
}
}
}
flag = !flag;
}
}
}
// 继承ReentrantLock类,定义静态常量锁
class LockA extends ReentrantLock {
private LockA() {
}
public static final LockA LOCK_A = new LockA();
}
class LockB extends ReentrantLock {
private LockB() {
}
public static final LockB LOCK_B = new LockB();
}
程的停止:
stop()方法 已经过时,不推荐使用。
interrupt()方法 中断线程
interrupt方法的作用:
线程中有wait(),sleep()等方法,这时会抛出一个InterruptException异常,并且清楚中断。
2.调用interrupt方法时,线程中没有上述方法,这时会设置(改变)中断状态的值(true---false)。
public class Test {
public static void main(String[] args) throws InterruptedException {
TestRunnable runnable = new TestRunnable();
Thread t1 = new Thread(runnable);
t1.start();
t1.interrupt();
}
}
class TestRunnable implements Runnable {
@Override
public void run() {
while (!Thread.interrupted()) {
System.out.println("我是子线程" + ".......run");
}
}
}
标记法
声明一个标识,用来停止线程
public class Test {
public static void main(String[] args) throws InterruptedException {
TestRunnable runnable = new TestRunnable();
Thread t1 = new Thread(runnable);
t1.start();
Thread.currentThread().sleep(3000);
runnable.flag = true;
}
}
class TestRunnable implements Runnable {
// 声明一个标记,用来控制线程
public boolean flag = false;
@Override
public void run() {
while (!flag) {
System.out.println("我是子线程" + ".......run");
}
}
}