一、线程安全出现的原因
在使用多线程的时候,往往会出现线程安全的问题,我们直到一个共享数据是可以由多个线程一起操作的,但是当一个共享数据在被一个线程操作的过程中,操作未被执行完毕,而此时另一个线程参与进来操作该共享数据,就会导致共享数据存在安全问题
二、解决线程安全问题
解决线程安全问题的办法就是当共享数据被一个线程操作完毕后,才能允许其他线程进行操作,所以这里有两个解决线程安全问题的方法,一个是同步代码块,即给操作共享数据的代码加上一个锁(也叫同步监视器),另一个就是同步方法
三、实现线程安全的方法
1、锁(同步监视器)
在JAVA中,给操作共享数据的代码加上锁的方式为:
synchronized(锁){
}
利用synchronized关键字就可以给代码加上锁,该关键字后面的小括号内所放入的就是锁,锁可以是一个任意的类,但是所有线程必须共用一个锁。下面是锁的使用的例子
class test implements Runnable{
int i =
100;
Object obj = new Object();
public void run(){
while(true )
{
synchronized(obj){//添加锁
if(i>0)
{
System.out.println(Thread.currentThread().getName()+ ":"i--);
}
else{
break;
}
}
}
}
}
二、同步方法
同步方法与同步代码块不同的地方就是将子线程要允许的代码放到一个方法中,在该方法的名字前面加上synchronized关键字即可,在这里默认的锁为this,所以,通过继承Thread类创建的多线程是不能够使用同步方法的。具体使用方法如下
class SellTicket1 implements Runnable{
int ticket =
200;
public void run(){
while(true ){
show();
}
}
public synchronized void show(){
if(ticket >0)
{
System. out.println(Thread.currentThread().getName()+ ":"+ticket --);
}
}
}
三、死锁问题
死锁产生的原因就是不同的线程都占用着对方需要的同步资源不放弃,都在等待对方释放自己需要的同步资源,从而形成了死锁,因此,在敲代码的时候应该避免死锁- -
四、线程通信
线程通信方面有三个可以使用的关键字,它们分别是
1、wait() 另当前的线程挂起,放弃CPU与同步资源,从而可以使别的线程访问并操作共享资源,而当前线程等候再次对资源的访问,也就是说,当线程运行到wait()时,就释放当前的锁
2、notify()/notifiAll() 唤醒一个或所有wait的线程
以上这三个方法,它们只能在synchronized代码块或synchronized方法中使用,否则会出现常java.lang.IllegalMonitorStateException
下面是一个例子两个线程交替打印1~100
/*
* 实现1~100数字的交替打印
*/
public class TestCommunication
{
public static void main(String[] args){
test2 p = new test2();
Thread P1 = new Thread(p );
Thread P2 = new Thread(p );
P1.setName( "线程1");
P2.setName( "线程2");
P1.start();
P2.start();
}
}
//创建线程
class test2 implements Runnable{
int num =
1;
public void run(){
while(true ){
synchronized(this ){
notify(); //唤醒
if(num <=100){
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e )
{
e.printStackTrace();
}
System. out.println(Thread.currentThread().getName()+ ":"+num );
num++;
} else{
break;
}
try {
wait(); //挂起
} catch (InterruptedException e )
{
e.printStackTrace();
}
}
}
}
}