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:
没有解决高度耦合。

posted @ 2020-02-25 14:14  Ysalng  阅读(155)  评论(0编辑  收藏  举报