zoukankan      html  css  js  c++  java
  • Java多线程设计模式系列

    通过几天的认真阅读,发现这是一本难得一见的好书,为了加深巩固学习成功,我打算将书中的例子全部自己实现一遍,特此记录下来也方便其他朋友学习。

    第一章,java语言的线程

    单线程程序:打印10000次good字符串

    public class SingleThreadSample {
    	public static void main(String[] args) {
    		for(int i=0; i< 10000; i++){
    			System.out.print("good!");
    		}
    	}
    }
    

    严格的说并不是只有一个线程在操作,还有其他的线程在非java处理系统上运行,比如gc,gui相关的线程等。

    第一个多线程程序:实现了交替打印good和nice的功能

    public class MyThreadTest {
    
    	public static void main(String[] args) {
    		MyThread t = new MyThread();
    		t.start();
    
    		for (int i = 0; i < 10000; i++) {
    			System.out.println("good!");
    		}
    	}
    }
    
    class MyThread extends Thread {
    
    	@Override
    	public void run() {
    		for (int i = 0; i < 10000; i++) {
    			System.out.println("nice!");
    		}
    	}
    }
    

    这里加入一个并发和并行概念的区别,并发是concurrent,是指多个线程在同一个cpu上切换进行执行。并行是parallel,指多个线程是在各自的cpu上同时执行的。

    我们增强一下刚才的多线程例子,把打印的字符串变成通过参数传递。

    public class MyThread2Test {
    	public static void main(String[] args) {
    		MyThread2 t1 = new MyThread2("good!");
    		MyThread2 t2 = new MyThread2("nice!");
    		
    		t1.start();
    		t2.start();
    	}
    	
    }
    
    class MyThread2 extends Thread {
    	private String message;
    
    	public MyThread2(String message) {
    		this.message = message;
    	}
    
    	@Override
    	public void run() {
    		for (int i = 0; i < 10000; i++) {
    			System.out.println(message);
    		}
    	}
    }
    

      

    刚才是通过集成Thread抽象类的子类方式实现多线程,另外还可以通过Runnable接口的方式,例子如下:

    public class MyThread3Test {
    	public static void main(String[] args) {
    		MyThread3 t1 = new MyThread3("good!");
    		MyThread3 t2 = new MyThread3("nice!");
    		
    		new Thread(t1).start();
    		new Thread(t2).start();
    	}
    }
    
    class MyThread3 implements Runnable {
    	private String message;
    
    	public MyThread3(String message) {
    		this.message = message;
    	}
    
    	@Override
    	public void run() {
    		for (int i = 0; i < 10000; i++) {
    			System.out.println(message);
    		}
    	}
    }
    

      

    启动和执行多线程已经说完了,那么该说说如何让线程休息休息。

    第一种方式是通过Thread.sleep(ms)方法,需要注意的是这个方法有一个重载Thread.sleep(ms,ns),可以把停止的时间控制到纳秒级。

    另外Thread.yield()方法也可以在循环体中使用,表示如果没有cpu时间则将当前线程切换到其他子线程,可以简单理解成Thread.sleep(0);

     不过Thread.sleep会抛出InterruptedException异常,Thread.yield不会。

    下面在说说线程互斥,还是刚才的例子,如果我打算让程序执行10000次打印的过程是一个整体,执行过程中不允许切换到其他子线程,那么就需要使用Synchronzed关键字。

    public class MyThreadMutualTest {
    	public static void main(String[] args) {
    		PrintMessage pmsg = new PrintMessage();
    
    		new MyThreadMutual(pmsg,"good").start();
    		new MyThreadMutual(pmsg,"nice").start();
    	}
    }
    
    class MyThreadMutual extends Thread {
    	private String message;
    	private PrintMessage printMessage;
    
    	public MyThreadMutual(PrintMessage printMessage,String message) {
    		this.printMessage = printMessage;
    		this.message=message;
    	}
    
    	@Override
    	public void run() {
    		printMessage.show(message);
    	}
    }
    
    class PrintMessage {
    
    	public synchronized void show(String msg) {
    		for (int i = 0; i < 10000; i++) {
    			System.out.println(msg);
    			try {
    				Thread.sleep(10);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

      

     

    接下来讲一下线程的协调,主要有三个方法:wait() notify() notifyAll()

    这三个方法都是object类的方法,可以理解成一个休息室,调用obj.wait()方法表示当前执行的线程进入休息室,休息室里可能会有多个线程,如果没有其他线程给休息室发消息通知它们可以出去了,这些线程就会一直在里面休息。

    当调用obj.notify()方法,表示休息室中可以有一个线程退出,如果里面有多个线程,会随机选取一个,而obj.notifyAll()表示所有的线程都可以退出休息室。

    现在把上面的例子修改一下,想打印10次good再打印10次nice,这样交替执行。

    public class ThreadMutualTest2 {
    	public static void main(String[] args) {
    		Object obj = new Object();
    		MyThreadMutualA a = new MyThreadMutualA("nice", obj);
    		MyThreadMutualB b = new MyThreadMutualB("good", obj);
    		
    		a.start();
    		b.start();
    	}
    }
    
    class MyThreadMutualA extends Thread {
    	private Object obj;
    	private String message;
    	
    	public MyThreadMutualA(String message, Object obj) {
    		this.message=message;
    		this.obj=obj;
    	}
    
    	@Override
    	public  void run() {
    		synchronized(obj){
    			for(int i=1; i<100; i++){
    				System.out.println(message);
    				
    				if(i%5==0){
    					obj.notify();
    					
    					try {
    						obj.wait();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    			
    			obj.notify();
    		}
    	}
    }
    
    class MyThreadMutualB extends Thread {
    
    	private Object obj;
    	private String message;
    	
    	public MyThreadMutualB(String message, Object obj) {
    		this.message=message;
    		this.obj=obj;
    	}
    
    	@Override
    	public synchronized void run() {
    		synchronized(obj){
    			for(int i=1; i<100; i++){
    				System.out.println(message);
    				if(i%5==0){
    					obj.notify();
    					
    					try {
    						obj.wait();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    			
    			obj.notify();
    		}
    	}
    }
    

      

    这段代码废了好大劲啊,同步互斥是多线程最复杂的最核心的部分了。

  • 相关阅读:
    基于Entity Framework的自定义分页,增删改的通用实现
    基于Dapper的分页实现,支持筛选,排序,结果集总数,多表查询,非存储过程
    让Windows 7变成WIFI热点
    composer update 总是出错解决方法
    yarn install 总是提示 waiting 解决办法
    eclipse 启动错误 : org.eclipse.jdt.internal.ui.javaeditor.ASTProvider$ActivationListener 解决
    gulp wxml gulp-htmlmin input不闭合的问题临时解决
    vscode+xdebug+cli 带参数配置
    vscode+php+xdebug Time-out connecting to client (Waited: 200 ms)
    vscode+php+xdebug won't stop at breakpoint 断点不起作用
  • 原文地址:https://www.cnblogs.com/gaotianle/p/3306971.html
Copyright © 2011-2022 走看看