线程安全的方式
线程不安全是因为多个线程同时执行同一段内容,如果内容更改未完成,则出现不安全问题
实现线程安全就是将本可以多个线程同步执行的,改为即使建立多个线程,也要排队使用,线程安全就会带来效率变低的问题。
方案一:同步代码块
格式:synchronized(锁对象){}
将需要安全的线程内容放入代码块中,其中的锁对象可以是任意一个Object对象,同一个锁的对象应该用同一把锁,所以锁的建立应该在run()方法外。
在同步代码块内的内容同一时间只能执行一个。其余的线程也要按照顺序来进行执行。
方案二:同步方法
与同步代码块类似都是使用synchronized关键字,不过同步方法是用关键字修饰方法。
格式:public synchronized void lmzaixxq(){}
该方式是通过关键字来修饰方法,被修饰的方法在执行时只能排队执行。
同时这里需要注意一个大家平时忽略的问题,首先synchronized锁的是括号里的对象,而不是代码,其次,对于非静态的synchronized方法,锁的是对象本身也就是this。
当synchronized锁住一个对象之后,别的线程如果想要获取锁对象,那么就必须等这个线程执行完释放锁对象之后才可以,否则一直处于等待状态。
方案三:显示锁
线程在执行时,是可以任意的执行任务的,但是我们可以采用一种方式让其被占用后不能被其他线程再次调用,该方法就是将其上锁。
在任务中创建锁的对象。
public class Demo {
public static void main(String[] args) {
Runnable run = new MyRunnable();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
}
class MyRunnable implements Runnable{
//在任务中创建锁对象
private Lock l = new ReentrantLock();
private int count = 10;
@Override
public void run() {
while (true) {
//调用锁的方法
l.lock();
if (count>0) {
System.out.println("throw tick");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("residual tick number:" + count);
}else break;
//使用完毕该内容,解开锁,允许其他线程进行调用,根据抢占法,所有线程开始抢占执行线程。
l.unlock();
}
}
}
锁的建立其实就是线程执行中的一个先后判断的顺序,一旦建立了锁,就是排队执行线程,根据抢占式的方法来进行抢占。
将三种方法再进行一下分类,其实是同步代码块和同步方法属于隐式锁,显示锁是单独的一个。
所以可以看出为实现线程安全,其实都是锁的建立,只是隐式锁是通过关键字的修饰来实现的。