Java对于多线程的安全问题提供了专业的解决方式:同步机制【锁】
同步代码块
synchronized (对象){
// 需要被同步的代码;
}
继承同步
class Window extends Thread{
private static int ticket = 100;
//定义同步监视器,多个线程共同使用唯一的同步监视器
private static Object dog = new Object(); // static确保监视器唯一
@Override
public void run() {
while (true){
synchronized (dog){
if (ticket > 0){
System.out.println("卖票, 票根为:" + ticket);
ticket--;
}else{
break;
}
}
}
}
}
class Window extends Thread{
private static int ticket = 100;
@Override
public void run() {
while (true){
synchronized (Window.class){ / 唯一的
if (ticket > 0){
System.out.println("卖票, 票根为:" + ticket);
ticket--;
}else{
break;
}
}
}
}
}
实现同步
不同步
class Window implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true){
if (ticket > 0){
System.out.println("卖票, 票根为:" + ticket);
ticket--;
}else{
break;
}
}
}
}
同步
class Window implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true){
// synchronized (Window.class){
synchronized (this){
if (ticket > 0){
System.out.println("卖票, 票根为:" + ticket);
ticket--;
}else{
break;
}
}
}
}
}
同步方法
synchronized还可以放在方法声明中,表示整个方法为同步方法。
例如:
public synchronized void show (String name){
….
}
class Window extends Thread{
private static int ticket = 100;
@Override
public void run() {
while (true){
show();
if (ticket <= 0){
break;
}
}
}
private static synchronized void show(){ // static保证唯一
//private synchronized void show(){ // error: 不是唯一
if (ticket > 0){
System.out.println("卖票, 票根为:" + ticket);
ticket--;
}
}
}
public class testT {
// 创建Thread子类对象,即创建了线程对象。
public static void main(String[] args) {
Window w1 = new Window();
Window w2 = new Window();
Window w3 = new Window();
w1.start();
w2.start();
w3.start();
}
}
继承同步
感觉下面的应该是同步安全的??????????????????【存在疑问】
class Window extends Thread{
private int ticket = 100;
@Override
public void run() {
while (true){
show();
if (ticket <= 0){
break;
}
}
}
private synchronized void show(){ // cwu
if (ticket > 0){
System.out.println("卖票, 票根为:" + ticket);
ticket--;
}
}
}
public class testT {
// 创建Thread子类对象,即创建了线程对象。
public static void main(String[] args) {
Window w1 = new Window();
Thread r1 = new Thread(w1);
Thread r2 = new Thread(w1);
Thread r3 = new Thread(w1);
r1.start();
r2.start();
r3.start();
}
}
实现同步
class Window implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true){
show();
if (ticket <= 0){
break;
}
}
}
private synchronized void show(){
if (ticket > 0){
System.out.println("卖票, 票根为:" + ticket);
ticket--;
}
}
}
其他
synchronized的锁是什么
- 任何对象都可以作为同步锁。所有对象都自动含有单一的锁
- 同步方法的锁: 静态方法(类名.class)、非静态方法(this)
- 同步代码块:自己指定,很多时候也是指定为this或类名.class
注意:
- 必须确保使用同一个资源
## 同步的范围
明确哪些代码存在线程安全问题
- 明确哪些代码是多线程运行的代码
- 明确多个线程是否有共享数据
- 明确多线程运行代码中是否有多条语句操作共享数据
如何解决?
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其
他线程不可以参与执行。
即所有操作共享数据的这些语句都要放在同步范围中
范围太小:没锁住所有有安全问题的代码
范围太大:没发挥多线程的功能
锁的释放
释放锁的操作
- 当前线程的同步方法,同步代码块执行结束
- 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
- 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
- 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。
不会释放锁的操作
- 线程执行同步代码块或者同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
- 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程
挂起,该线程不会释放锁(同步监视器)。- 应尽量避免使用suspend()和resume()来控制线程