zoukankan      html  css  js  c++  java
  • Java -- 线程

    1. 创建线程(一)

    定义线程类, 继承Thread 并重写run(), run()称为线程体。

    单继承限制,尽量少用。
    class firstThread extends Thread {    //创建线程类
    public void run(){                      //重写run() 
    for(int i=0; i<100; i++)  
       System.out.println("Thread --->" + i);  
     }
    }

    public class main {
     public static void main(String[] args) {  
      firstThread ft = new firstThread();     //生成线程类对象
      ft.start();                             //启动线程  不能直接ft.run()
      for(int i=0; i<100; i++)  
       System.out.println("main --->" + i); 
     
    }

     创建线程(二)

    实现接口Runnable, 并将其对象传入 Thread构造函数,生成Thread对象。

    class RunnableImpl implements Runnable  
     public void run() {
      for(int i=0; i<100; i++)  
       System.out.println("Runnable --->" + i);   
     
    }

    public class main {
     public static void main(String[] args) {  
            //生成一个Runnable接口实现类的对象    
      RunnableImpl ri = new RunnableImpl();
      Thread thread = new Thread(ri); //生成Thread对象,并将ri作为参数。
      thread.start();
      
      for(int i=0; i<100; i++)  
       System.out.println("main --->" + i); 
     
    }

    两种方法对比:

    继承Thread类:   编写简单,不必使用Thread.currentThread(),直接this.getName()即可。 但是不能再继承其他类了。。

    实现Runnable接口: 可再继承其他类,可以多线程共享一个目标对象,但是编写略复杂,访问当前线程需要用Thread.currentThread()。

    2. Join 线程等待

    public class Main extends Thread{
    
    	private int i;
    	public Main(String name)
    	{
    		super(name);
    	}
    	public void run()
    	{
    		for(; i<100; i++)
    		{
    			System.out.println(getName() + " " + i);
    		}
    	}
    	
    	public static void main(String[] args) throws InterruptedException
    	{
    		Main thread1 =  new Main("1");
    		Main thread2 =  new Main("2");
    		
    		for(int i=0; i<100; i++)
    		{
    			if( i==20 )
    			{
    				thread1.start();
    				thread1.join(); //一直阻塞到线程1结束
    				thread2.start();				
    			}
    		}
    	}
    }

    3. 后台线程 (守护线程) : JVM垃圾回收线程就是典型的后台线程,如果所有的前台线程都死亡,后台线程会自动死亡。

    调用Thread对象的setDaemon(true)则可以设置线程为后台线程。

    例如上面的  thread1.setDaemon(true);  即可。。

    4. 线程让步 和 优先级设置

    使用Thread的静态方法  Thread.yield()即可, 让步后线程并不是进入阻塞态,而是进入就绪态 重新竞争。

    设置线程优先级可以用 thread1.setPriority(int ...) ; 输入参数可以为 MAX_PRIORITY 值为10, MIN_PRIORITY 1, NORM_PRIORITY 5.

    5. 同步代码块 synchronized

    可以使用同步代码块,锁定临界资源 synchronized(Object obj){... ....}

    public void run()
     {
      Integer i;
      for(i=0; i<100; i++)
      { 
       synchronized(i)  //同步代码块
       {
        System.out.println(getName() + " " + i);
       }
      }
     }

    还可以用synchronized 修饰类的方法,让该方法变为线程安全。

    例如  public synchronized void draw() { ... ... }

    6. 同步锁    ReadWriteLock(读写锁) ReentrantLock(可重入锁) 

    class A
    {
    	private final ReentrantLock lock = new ReentrantLock();  //定义锁对象
    	public void fun() 
    	{
    		lock.lock();   //加锁
    		try
    		{
    			// 需要 线程安全的代码
    		}
    		finally
    		{
    			lock.unlock();  //解锁
    		}
    	}
    }


    7.线程通信

    利用wait() 当前线程等待   notify()唤醒在同步监视器上等待的单个线程。  notifyAll()唤醒在同步监视器上的所有线程。

    class A   //属性 num 加一  减一
    {
    	private Boolean putflag = false;
    	private Integer num = 0;
    	
    	public synchronized void get()
    	{
    		try
    		{
    			if( !putflag )
    			{
    				wait();   //阻塞
    			}
    			else
    			{				
    				num--;
    				System.out.println(Thread.currentThread().getName() + " get " + num);
    				putflag = false;
    				notifyAll();  //唤醒
    			}			
    		}
    		catch (InterruptedException e)
    		{
    			e.printStackTrace();
    		}
    	}
    	
    	public synchronized void put()
    	{
    		try
    		{
    			if( putflag )
    			{
    				wait();
    			}
    			else
    			{				
    				num++;
    				System.out.println(Thread.currentThread().getName() + " put " + num);
    				putflag = true;
    				notifyAll();
    			}
    		}
    		catch (InterruptedException e)
    		{
    			e.printStackTrace();
    		}
    	}		
    }
    
    class Get extends Thread
    {
    	private A a;
    	private String name;
    	public Get(String name, A a)
    	{
    		this.name = name;
    		this.a = a;		
    	}
    	public void run()
    	{
    		for(int i=0; i<10; i++)
    		{
    			System.out.println(name);
    			a.get();  //减一
    		}
    	}
    }
    
    class Put extends Thread
    {
    	private A a;
    	private String name;
    	public Put(String name,A a)
    	{
    		this.name = name;
    		this.a = a;
    	}
    	public void run()
    	{
    		for(int i=0; i<10; i++)
    		{
    			System.out.println(name);
    			a.put();  //加一
    		}
    	}
    }
    
    
    public class Main extends Thread{
    		
    	public static void main(String[] args)
    	{
    		A a = new A();
    		new Get("lisi", a).start();
    		new Put("wangwu", a).start();
    		new Put("zhangsan", a).start();		
    	}	
    }

    输出效果是  加一 减一 交替进行。
    如果不是用synchronized来保证同步的,如果是用lock, 可以用Condition来做协调

    如下只需修改Class A

    class B
    {
    	private final Lock lock = new ReentrantLock();  //定义一个锁 lock
    	private final Condition cond = lock.newCondition();  //定义 Condition
    	public void put()
    	{
    		lock.lock();
    		try
    		{
    			if( !flag )
    			{
    				cond.await();  //阻塞
    			}
    			else
    			{
    				.... .....
    				cond.signalAll();  //唤醒
    			}
    		}
    	}
    	
    }
    

    使用管道线程间通信

    管道字节流: PiedInputStream PieOutputStream  管道字符流: PipedReader PipedWriter  新IO管道Channel: Pipe.SinkChannel PipeSourceChannel

    class ReaderThread extends Thread
    {
    	private PipedReader pr;       //输入管道
    	private BufferedReader br;   
    	public ReaderThread(PipedReader pr)
    	{
    		this.pr = pr;
    		this.br = new BufferedReader(pr);
    	}
    	public void run()
    	{
    		String buf = null;
    		try
    		{
    			while( (buf=br.readLine()) != null )
    			{
    				System.out.println("Reader: " + buf);
    			}
    		}
    		catch (IOException e)
    		{
    			e.printStackTrace();
    		}
    		finally
    		{
    			try {
    				br.close();
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    }
    
    class WriterThread extends Thread
    {
    	String[] strs = new String[]{ "1234", "5678", "qwer", "asdf" };
    	private PipedWriter pw;  //写管道
    	public WriterThread(PipedWriter pw)
    	{
    		this.pw = pw;		
    	}
    	public void run()
    	{
    		try
    		{
    			for(int i=0; i<10; i++)
    			{
    				pw.write(strs[i%4] + "
    ");
    				System.out.println("Writer" + strs[i%4]);
    			}
    		}
    		catch(IOException e)
    		{
    			e.printStackTrace();
    		}
    		finally
    		{
    			try {
    				pw.close();
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    	
    }
    
    public class Main extends Thread{
    		
    	public static void main(String[] args)
    	{
    		PipedReader pr = null;
    		PipedWriter pw = null;
    		try
    		{
    			pw = new PipedWriter();
    			pr = new PipedReader();
    			pw.connect(pr);           //管道连接
    			new WriterThread(pw).start();   //开启读写线程
    			new ReaderThread(pr).start();
    		}
    		catch(IOException e)
    		{
    			e.printStackTrace();
    		}
    	}	
    }



     

     
     

  • 相关阅读:
    .NET Core微服务开发服务间调用篇-GRPC
    .NET Core微服务开发网关篇-ocelot
    刷新.NET
    (译)An introduction to Kubernetes
    一文了解Nuget的使用
    .NET Core应用框架AA介绍(二)
    .NET Core 3.0 使用Nswag生成Api文档和客户端代码
    .NET core3.0 使用Jwt保护api
    阅读源码学设计模式-单例模式
    .NET Core 3.0 部署在docker上运行
  • 原文地址:https://www.cnblogs.com/xj626852095/p/3648172.html
Copyright © 2011-2022 走看看