-
线程安全原因
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
-
线程安全解决方法
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
-
同步机制
Java对于多线程的安全问题提供了专业的解决方式:
/*
* 1、线程存在安全问题的原因
* 由于一个线程在操作共享数据的过程中,未执行完毕的情况下,另外的线程参与进来,导致了共享数据存在安全问题。
*
* 2、如何解决数据的安全问题
* 必须让一个线程操作完共享数据之后,其他线程才有机会参与共享数据的操作。
*
* 3、Java如何现成的安全,线程的同步机制
* (1):同步代码块
* synchronized(同步监视器){
* //需要被同步的代码块(即为操作共享数据的代码)
* }
* 共享数据:多个线程共同操作的同一个数据(或者变量)。
*
* 同步监视器:有一个类(可创建实例的类)的对象来充当。
哪一个线程获取此监视器(就是锁),谁就执行大括号里被同步的代码。所有的线程必须共用一把锁。
*注:在实现的方式中,同步代码块的监视器可以使用this来充当。但是在继承Thread的方式中,慎用this。
*
*
* (2):同步方法
* 将操作共享数据的方法声明为synchronized,即此方法为同步方法。
* >>同步方法的锁:this
*
* 4、线程同步的弊端:由于同一个时间内只有一个线程访问共享数据,效率变低。
*
*
* */
public class _001_TestSynchronous {
/* (1):同步代码块 */
private static class Windows implements Runnable {
private int tickets = 100;
@Override
public void run() {
// TODO Auto-generated method stub
Object object = new Object();
while (true) {
// 实现Runnable,object由this来代替,this表示当前对象;继承Thread慎用。
synchronized (object) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "售票,票号为:" + tickets--);
} else {
break;
}
}
}
}
}
private static class WindowsA extends Thread {
private static int tickets = 100;
private static Object object = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
Object object = new Object();
while (true) {
// 实现Runnable,object由this来代替,this表示当前对象;继承Thread时,this慎用。
synchronized (object) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "售票,票号为:" + tickets--);
} else {
break;
}
}
}
}
}
/* (2):同步方法 */
private static class WindowsB implements Runnable {
private int tickets = 700;//取数大一点
@Override
public void run() {
while (tickets>0) {
show();
}
}
public synchronized void show() {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "售票,票号为:" + tickets--);
}
}
}
public static void test() {
_001_TestSynchronous.Windows win = new _001_TestSynchronous.Windows();
Thread t = new Thread(win);
Thread tA = new Thread(win);
Thread tB = new Thread(win);
t.setName("win");
tA.setName("win1");
tB.setName("win2");
t.start();
tA.start();
tB.start();
}
public static void testA() {
_001_TestSynchronous.WindowsA win = new _001_TestSynchronous.WindowsA();
_001_TestSynchronous.WindowsA winA = new _001_TestSynchronous.WindowsA();
_001_TestSynchronous.WindowsA winB = new _001_TestSynchronous.WindowsA();
win.start();
winA.start();
winB.start();
}
public static void testB() {
_001_TestSynchronous.WindowsB win = new _001_TestSynchronous.WindowsB();
Thread t = new Thread(win);
Thread tA = new Thread(win);
Thread tB = new Thread(win);
t.setName("win");
tA.setName("win1");
tB.setName("win2");
t.start();
tA.start();
tB.start();
}
public static void main(String[] args) {
/*
* test();
testA();
*/
testB();
}
}