线程的同步和安全

如果多个线程同时运行同一个线程体,每次运行的结果可能都不一样

class MyThread implements Runnable{

	int i = 10;

	public void run(){

		while(true){

		//获取当前运行线程的名字

			System.out.println(Thread.currentThread().getName() + i);

			i--;

			Thread.yield();

			if(i < 0){

				break;

			}

		}

	}

}

class Test{

	public static void main(String args[]){

		MyThread mt = new MyThread();

		//生成共用同一线程体的两个线程对象

		Thread t1 = new Thread(mt);

		Thread t2 = new Thread(mt);

		//设置线程名字

		t1.setName("A线程:");

		t2.setName("B线程:");

		//分别启动两个线程

		t1.start();

		t2.start();

	}

}

线程的同步和安全

根据上图我们知道结果明显有错误,这就是多线程运行访问同一份数据时出现的错误。错误原因:AB线程轮流运行,假设B线程先运行了几行代码后(打印B线程:10)轮到A线程运行。A线程运行线程体后也打印A线程:10

为解决这个问题,我们使用java关键字:synchronized

class MyThread implements Runnable{

	int i = 10;

	public void run(){

		while(true){

			//同步代码块

			synchronized(this){

				//获取当前运行线程的名字

				System.out.println(Thread.currentThread().getName() + i);

				i--;

				Thread.yield();

				if(i < 0){

					break;	

				}

			}

		}

	}

}

线程的同步和安全

使用同步代码块后,当A线程执行线程体时,获得了对象锁的使用权,即使A线程运行到yield方法时仍持有这个锁的使用权,B线程没有得到对象锁的使用权,则需要等待A线程执行完线程体释放对象锁。当B线程获得了对象锁的使用权后A线程也需要等待。线程的同步是为了防止多个线程访问同一数据时,对数据造成的破坏。

 

同步代码块锁住的到底是什么呢?

class Service{

	public void fun1(){

		synchronized(this){

			try{

				Thread.sleep(3000);

			}

			catch(Exception e){

				System.out.println(e);

			}

			System.out.println("fun1");

		}

	}

	public void fun2(){

		synchronized(this){

			System.out.println("fun2");

		}

	}

}

class MyThread1 implements Runnable{

	private Service service;

	public MyThread1(Service service){

		this.service = service;

	}

	

	public void run(){

		service.fun1();

	}	

}

class MyThread2 implements Runnable{

	private Service service;

	public MyThread2(Service service){

		this.service = service;

	}

	

	public void run(){

		service.fun2();

	}

}

class Test{

	public static void main(String args[]){

		Service service = new Service();

		Thread t1 = new Thread(new MyThread1(service));

		Thread t2 = new Thread(new MyThread2(service));

		t1.start();

		t2.start();

	}

}

启动t1线程后,t1线程调用fun1方法,执行同步代码块休眠3秒钟,并持有对象锁。如果没有同步代码块,t1线程休眠则执行t2线程,但因为fun2方法的同步代码块的对象锁也是this,所以t2线程无法执行,需要等待t1线程释放对象锁。由此可见,synchronized锁住的是对象而不是代码块,一旦某一线程获得了某个对象的对象锁,那么这个对象的所有同步代码块其他线程都不能执行,需要等待对象锁的释放。

 

Synchronized除了用于同步代码块,还可用于同步方法,如

public synchronized void fun2(){

	System.out.println("fun2");

}

同步方法和同步代码块功能类似,但同步方法锁住的是this对象,同步代码块可以锁定除了this之外的指定对象。当一个线程调用对象的其中一个同步方法时,那么这个对象的其他同步方法也不能被其他线程使用。  

 

你可能感兴趣的:(线程的同步)