• JAVA多线程基础


    1. 多进程与多线程

    多进程

    • 每个独立执行的任务就是一个进程

    • 操作系统将时间划分为多个时间片,在每个时间片内将CPU分配给某一个任务,时间片结束,CPU将自动回收,再分配给其他任务

    • 多进程的缺点:比较笨重不好切换

    多线程

    • 一个程序可包多个子任务,可串并行

    • 一个子任务可以称为一个线程

    • 在一个线程阻塞时,CPU可以调度另一个线程工作,这样CPU还是保留在本程序中。

    2. java实现多线程的两种方法

    1.线程继承Thread类,实现run方法。

    public class Thread1 extends Thread{
    	public void run()
    	{
    		System.out.println("hello");
    	}
    	public static void main(String[] a)
    	{
    		new Thread1().start();
    	}
    }
    

    2.线程实现Runnable接口,实现run方法。(Runnable对象必须放在一个Thread类中才能运行)

    public class Thread2 implements Runnable{
    	public void run()
    	{
    		System.out.println("hello");
    	}
    	public static void main(String[] a)
    	{
    		new Thread(new Thread2()).start();
    	}
    }
    
    • start()方法会自动调用run方法

    • 直接调用run()方法,会变成串行执行

    • main函数(线程)可能遭遇新线程结束,整个程序并不终止

    • 整个程序终止时等所有的线程都终止

    3. 多线程信息共享

    应该注意两种实现方法信息共享的区别。

    • 继承Tread类,只能通过设置Static静态常量实现变量共享,静态变量只有一个值。
    public class ThreadDemo0
    {
    	public static void main(String [] args)
    	{
    		new TestThread0().start();
    		new TestThread0().start();
    		new TestThread0().start();
    		new TestThread0().start();
    	}
    }
    class TestThread0 extends Thread  
    {
    	//private int tickets=100;           //每个线程卖100张,没有共享
    	private static int tickets=100;  //static变量是共享的,所有的线程共享
    	public void run()
    	{
    		while(true)
    		{
    			if(tickets>0)
    			{
    				System.out.println(Thread.currentThread().getName() +
    				" is selling ticket " + tickets);
    				tickets = tickets - 1;
    			}
    			else
    			{
    				break;
    			}
    		}
    	}
    }
    
    
    • 实现Runnable接口,设置一个private常量,TestThread1变量只被创建一次,而new Thread(t).start()只是把t包装为不同的对象,所以使用的是同一个对象,普通成员变量即可共享信息。
    
    public class ThreadDemo1
    {
    	public static void main(String [] args)
    	{
    		TestThread1 t=new TestThread1();
    		new Thread(t).start();
    		new Thread(t).start();
    		new Thread(t).start();
    		new Thread(t).start();
    	}
    }
    class TestThread1 implements Runnable
    {
    	private int tickets=100;
    	public void run()
    	{
    		while(true)
    		{
    			if(tickets>0)
    			{
    				System.out.println(Thread.currentThread().getName() +" is selling ticket " + tickets);
    				tickets--;
    			}
    			else
    			{
    				break;
    			}
    				
    		}
    	}
    }
    

    但是上述方法会存在工作副本的问题,应该采用volatile关键字使变量可以再各个进程之间通信,以及使用互斥锁synchronized对关键步骤进行加锁限制

    //1.改写runnable接口方法
    public class ThreadDemo3 {
    	public static void main(String[] args) {
    		TestThread3 t = new TestThread3();
    		new Thread(t, "Thread-0").start();
    		new Thread(t, "Thread-1").start();
    		new Thread(t, "Thread-2").start();
    		new Thread(t, "Thread-3").start();
    	}
    }
    
    class TestThread3 implements Runnable {
    	private volatile int tickets = 100; // 多个 线程在共享的
    
    	public void run() {
    		while (true) {
    			sale();
    			try {
    				Thread.sleep(100);
    			} catch (Exception e) {
    				System.out.println(e.getMessage());
    			}
    			if (tickets <= 0) {
    				break;
    			}
    		}
    
    	}
    
    	public synchronized void sale() { // 同步函数
    		if (tickets > 0) {
    			System.out.println(Thread.currentThread().getName() + " is saling ticket " + tickets--);
    		}
    	}
    }
    
    
    //2.改写继承Thread类的方法
    public class ThreadDemo0
    {
    	public static void main(String [] args)
    	{
    		new TestThread0().start();
    		new TestThread0().start();
    		new TestThread0().start();
    		new TestThread0().start();
    	}
    }
    class TestThread0 extends Thread  
    {
    	volatile private static int tickets=100;  //static变量是共享的,所有的线程共享
    	public void run() {
    		while (true) {
    			sale();
    			try {
    				Thread.sleep(100);
    			} catch (Exception e) {
    				System.out.println(e.getMessage());
    			}
    			if (tickets <= 0) {
    				break;
    			}
    		}
    
    	}
    
    	public static synchronized void sale() { // 同步函数
    		if (tickets > 0) {
    			System.out.println(Thread.currentThread().getName() + " is saling ticket " + tickets--);
    		}
    	}
    }
    

    总结

    1.实现共享变量必须使这个变量的值只有一个。

    2.某段时间只有一个进程对这个值操作。

    3.应该让其他进程知晓这个变量的变化。

    4. 多线程管理

    4.1. 生产者消费者模型

    package product;
    
    /**
     *仓库
     */
    class Storage {
    	// 仓库容量为10
    	private Product[] products = new Product[10];
    	private int top = 0;
    
    	// 生产者往仓库中放入产品
    	public synchronized void push(Product product) {
    		while (top == products.length) {
    			try {
    				System.out.println("producer wait");
    				wait();//仓库已满,等待
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
            //把产品放入仓库
    		products[top++] = product;
    		System.out.println(Thread.currentThread().getName() + " 生产了产品"
    				+ product);
    		System.out.println("producer notifyAll");
    		notifyAll();//唤醒等待线程
    		
    
    	}
    
    	// 消费者从仓库中取出产品
    	public synchronized Product pop() {
    		while (top == 0) {
    			try {
    				System.out.println("consumer wait");
    				System.out.println(top);
    				wait();//仓库空,等待
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    
    		}
    
    		//从仓库中取产品
    		--top;
    		Product p = new Product(products[top].getId(), products[top].getName());
    		products[top] = null;
    		System.out.println(Thread.currentThread().getName() + " 消费了产品" + p);
    		System.out.println("comsumer notifyAll");
    		notifyAll();//唤醒等待线程
    		return p;
    	}
    }
    

    notify(),与notifyall()方法用来唤醒等待进程
    wait()方法等待

    4.2. 线程

    java线程的状态

    java的monitor监视器

    java的monitor监视器

    synchronized关键字

    5.java线程组:

    并行计算的模式:

    • 主从模式
    • worker模式

    线程组ThreadGroup:
    没有解决高度耦合。

  • 相关阅读:
    C++ 虚函数表解析(转载)
    javaWeb中的/路径问题
    java创建多线程(转载)
    JSP中pageEncoding和charset区别,中文乱码解决方案(转载)
    Class.forName()的作用与使用总结(转载)
    Java内存模型
    java-锁膨胀的过程
    java对象头信息和三种锁的性能对比
    并发容器
    synchronized和volatile以及ReentrantLock
  • 原文地址:https://www.cnblogs.com/innndown/p/12361493.html
Copyright © 2020-2023  润新知