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. 线程
5.java线程组:
并行计算的模式:
- 主从模式
- worker模式
线程组ThreadGroup:
没有解决高度耦合。