多线程示例代码:
public class ThreadTest {
public static void main (String[] args) {
Print p = new Print ();
new Thread (new Runnable () {//以匿名的实现Runnable接口的类为参数创建匿名线程并start()
@Override
public void run () {//重写的run()
while (true) {
p.print1 ();
}
}
}).start ();
new Thread (new Runnable () {
@Override
public void run () {
while (true) {
p.print2 ();
}
}
}).start ();new Thread (new Runnable () {
@Override
public void run () {
while (true) {
p.print3 ();
}
}
}).start ();
}
}
class Print {
public void print1 (){
System.out.print ("惊");
System.out.print("虹");
System.out.print ("留");
System.out.println ("恨");
}
public void print2 (){
System.out.print ("素");
System.out.print("还");
System.out.println("真");
}
public void print3 (){
System.out.print ("佛");
System.out.print("剑");
System.out.print ("分");
System.out.println ("说");
}
}
上面的代码创建了3个线程执行Print类的3个方法 结果如:
出现了 不规则的结果是因为当前线程的print()还没有运行完,执行权又被交给了其他的线程,导致输出混乱,要解决需要同步print()或则添加同步代码块:
1.声明方法为同步的:
public synchronized void print1 (){
System.out.print ("惊");
System.out.print("虹");
System.out.print ("留");
System.out.println ("恨");
}
2,添加同步代码块:
public void print2 (){
synchronized (this) {//這里的this是锁对象,可是是任何对象 别处要与他同步的代码块的锁必须和這里的this是同一对象,否则无法达到同步的目的
System.out.print ("素");
System.out.print("还");
System.out.println("真");
}
}
选择上面2种方法之一把print()3个方法进行处理就不会出现乱序了,一个线程执行的时候不会突然跳到其他线程 从而出现乱序字符
如果想一个线程执行一次方法打印一句又换另外的方法输出另外一句呢?
就需要实现线程间的通信:
什么时候需要通信
* 多个线程并发执行时, 在默认情况下CPU是随机切换线程的
* 如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
1.利用Object类的wait()和notify()方法:
怎么通信
* 如果希望线程等待, 就调用wait()
* 如果希望唤醒等待的线程, 就调用notify();
* 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
多个线程通信的问题
* notify()方法是随机唤醒一个线程
* notifyAll()方法是唤醒所有线程
* JDK5之前无法唤醒指定的一个线程
* 如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件
class Print {
static int n = 1;//添加标记变量n
public void print1 () throws InterruptedException {
synchronized (this) {
while (n != 1) {//只要n!=1 该线程就等待
this.wait ();
}
System.out.print ("惊");
System.out.print("虹");
System.out.print ("留");
System.out.println ("恨");
n=2;
this.notifyAll ();//修改标记变量唤醒其他在等待的所有线程
}
}
public void print2 () throws InterruptedException {
synchronized (this) {//這里的this是锁对象,可是是任何对象 要与他同步的代码块必须和這里的this是同一对象,否则无法达到同步的目的
while (n != 2) {
this.wait ();
}
System.out.print ("素");
System.out.print("还");
System.out.println("真");
n = 3;
this.notifyAll ();
}
}
public void print3 () throws InterruptedException {
synchronized (this) {
while (n != 3) {
this.wait ();
}
System.out.print ("佛");
System.out.print("剑");
System.out.print ("分");
System.out.println ("说");
n =1;
this.notifyAll ();
}
}
}
运行效果:
2.JDK1.5之后可是使用ReentrantLock 和Condition:
class Print {
static int n = 1;//添加标记变量n
ReentrantLock r = new ReentrantLock ();//创建互斥锁r
Condition c1 = r.newCondition ();//得到用来与此 Lock 实例一起使用的 Condition 实例
Condition c2 = r.newCondition ();
Condition c3 = r.newCondition ();
public void print1 () throws InterruptedException {
r.lock ();//加锁
if (n != 1) {//只要n!=1 c1条件就等待
c1.await ();
}
System.out.print ("惊");
System.out.print ("虹");
System.out.print ("留");
System.out.println ("恨");
n = 2;
c2.signal ();//点名唤醒c2条件
r.unlock ();//解锁
}
public void print2 () throws InterruptedException {
r.lock ();
if (n != 2) {
c2.await ();
}
System.out.print ("素");
System.out.print ("还");
System.out.println ("真");
n = 3;
c3.signal ();
r.unlock ();
}
public void print3 () throws InterruptedException {
r.lock ();
if (n != 3) {
c3.await ();
}
System.out.print ("佛");
System.out.print ("剑");
System.out.print ("分");
System.out.println ("说");
n = 1;
c1.signal ();
r.unlock ();
}
}
与synchronized相比,不同的线程使用不同的Condition, 这样就能区分唤醒哪个线程了.功能更强大.
如果目标不是运行方法而是可以装入容器实例的话(比如生存者和消费者的栗子),还可以使用更方便的ArrayBlockingQueue阻塞队列还实现,更加的方便