java中的线程同步

在java中,每一个线程都是由Thread类对象创建和控制的。通常我们有两种方式来创建一个线程,一种是继承java.lang.Thread 类,第二种是创建类的时候实现Runnable接口。下面分别介绍两种方式。

1,继承Thread类
首先创建Thread子类的一个实例,然后重写run方法,然后子类的实例必须调用start()方法之后run方法才被执行. 代码如下:
public class MultiThread extends Thread {
	public void run() {
		System.out.println(getName()+"线程开始运行");
		for(int i = 0; i< 10; i++) {
			System.out.println(i +" "+getName());
			try{
				sleep((int) Math.random()*10);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(getName() + "线程结束");
	}
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName()+"线程开始运行");
		new MultiThread().start();
		System.out.println(Thread.currentThread().getName()+"线程结束");	
	}
}


2,实现Runnable接口
首先我们创建一个实现Runnable接口的类ThreadRunnable,为了让线程可以执行接口中的run()方法,我们要在Thread类的构造函数中传入ThreadRunnable的一个实例,这样线程就可以执行run方法。代码如下:
public class ThreadRunnable implements Runnable {
	public int count = 0;
	public void run() {
		System.out.println("线程开始运行");
		try {
			while(count <3){
				Thread.sleep(300);
				count++;
			}
		}catch (InterruptedException e) {
			System.out.println("线程终止");
		}
		System.out.println("线程结束");
	}	
	
	public static void main(String[] args) {
		ThreadRunnable instance = new ThreadRunnable();
		Thread  thread = new Thread(instance);
		thread.start();
	}
}


当我们创建线程的时候,我们一般倾向于实现一个Runnable接口。因为java中不支持多重继承,如果我们继承了Thread类,那这个类就不能继承其他的类了,而如果我们实现了Runnable接口我们还可以继承其它的类。有些时候我们可能仅仅需要让线程运行就可以,当我们继承了Thread类,我们却继承了Thread类所有的方法,过于浪费。

上面简单介绍了java中如何创建线程,下面讨论一下多线程的问题。
在同一程序中运行多个线程本身不会导致问题,但如果多个线程同时访问并修改了相同的资源,就会导致问题。值得我们注意的是,这些问题只有在多个线程向这些资源做了写操作时才有可能发生,多个线程读取相同的资源就是安全的。
下面我们举个例子:
public class ThreadAdd {
	public static void main(String[] args) {
		MyThread instence = new MyThread();
		Thread thread0 = new Thread(instence);
		Thread thread1 = new Thread(instence);
		thread0.start();
		thread1.start();
	}
}
class MyThread implements Runnable {
	private int sum = 0;
	public void run() {
		{
			if(Thread.currentThread().getName().equals("Thread-0")){
				sum += 2;
			}else if(Thread.currentThread().getName().equals("Thread-1"))
				sum += 3;
			System.out.println(sum);
		}
	}	
}

上面的代码中thread0 和thread1执行同一个MyThread对象的方法,我们期望sum最后的结果为5,但事实上sum可能为 2,3,5。导致这个结果的原因时线程在程序中是交错执行的。当两个线程竞争同一个资源时,如果对资源的访问顺序敏感,就出现了这种情况,我们称它为竞态条件,导致竞态条件的方法称为临界区,为了避免这种情况,我们往往在临界区中使用相应的同步机制。常用的有Synchronized,Mutex, Lock和Semaphore。

对于上面的例子我们可以任意选择一种同步机制,例如使用synchronized:
public void run() {
	synchronized(this){
		if(Thread.currentThread().getName().equals("Thread-0")){
			sum += 2;		
		}else if(Thread.currentThread().getName().equals("Thread-1"))
			sum += 3;
		System.out.println(sum);
	}
}	

这样就可以保证sum的最终结果为5。
对于同步锁还有信号量的问题在其他文章里详细介绍。

猜你喜欢

转载自kickcode.iteye.com/blog/2261585