多线程详解

一.线程和进程

进程:进程是执行中的代码,严格的来说,进程不仅仅是程序代码,还包括运行在CPU 中的一系列数据,包括全局变量和临时数据等等。

线程:线程是CPU使用的基本单元,它由线程ID,程序计数器,寄存器集合和栈组成。

线程和进程的关系:一个进程至少包括一个线程,一个或者多个线程组成一个进程,进程和线程是一对多的关系。

二.CPU调度

关于CPU调度的内容过多,所以这里解释2个部分内容,分别是FIFO调度和轮转法调度

FIFO调度:先到先服务调度,即谁先到达谁最先执行。

轮转法调度:CPU将自身的使用时间分成一个小的时间片,每一个时间片执行一个进程或线程。教学视频中的调度方法应该就是这一种。

三.线程状态

java中规定的线程状态有一下5种:

  • NEW
    至今尚未启动的线程处于这种状态。
  • RUNNABLE
    正在 Java 虚拟机中执行的线程处于这种状态。
  • BLOCKED
    受阻塞并等待某个监视器锁的线程处于这种状态。
  • WAITING
    无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。
  • TIMED_WAITING
    等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。
  • TERMINATED
    已退出的线程处于这种状态。


上述为状态切换图。

四.线程的创建

java线程的创建有继承Thread和实现Runnable两种方法,相比较而言第二种方法更为常见也更为方便。

五.线程同步

由于采用时间片制度,当run()方法中执行的操作过多时,就会出现在一个时间片不能执行完毕的情况,这种情况下线程执行会混乱,可能产生不可知和错误的数据,这个时候就要用到同步函数和同步代码块,关键字是synchronized。

同步的前提:

        a,必须要有两个或者两个以上的线程。

        b,必须是多个线程使用同一个锁。

同步的利弊:

        好处:解决了多线程的安全问题。

        弊端:多个线程需要判断锁,较为消耗资源。

如何寻找多线程中的安全问题:

        a,明确哪些代码是多线程运行代码。

        b,明确共享数据。

        c,明确多线程运行代码中哪些语句是操作共享数据的。

静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class。

public class ThreadSafeTest implements Runnable {
	int num = 10; // 设置当前总票数
	
	public void run() {
		while (true) {
			if (num > 0) {
				try {
					Thread.sleep(100);
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println("tickets" + num--);
			}
		}
	}
	
	public static void main(String[] args) {
		ThreadSafeTest t = new ThreadSafeTest(); // 实例化类对象
		Thread tA = new Thread(t); // 以该类对象分别实例化4个线程
		Thread tB = new Thread(t);
		Thread tC = new Thread(t);
		Thread tD = new Thread(t);
		tA.start(); // 分别启动线程
		tB.start();
		tC.start();
		tD.start();
	}
}

六.死锁

在多线程情况下,多个线程可能竞争一定数量的资源,某个线程申请资源,如果这个资源不可用,那么该程序进入等待状态,如果所申请的资源被其他等待线程所占有,那么该线程可能再也无法进入等待状态,这种情况称为死锁,为了避免死锁,请不要在同步函数中内嵌同步函数,这会导致非常严重的死锁问题

七.JDK1.5中提供了多线程升级方案

将同步替换成现实Lock操作,将Object中的wait,notify,notifyall,替换了Condition对象。

该对象可以从Lock锁进行获取。

/*
生产者生产商品,供消费者使用
有两个或者多个生产者,生产一次就等待消费一次
有两个或者多个消费者,等待生产者生产一次就消费掉

*/

import java.util.concurrent.locks.*;

class Resource 
{	
	private String name;
	private int count=1;
	private boolean flag = false;
	
	//多态
	private Lock lock=new ReentrantLock();

	//创建两Condition对象,分别来控制等待或唤醒本方和对方线程
	Condition condition_pro=lock.newCondition();
	Condition condition_con=lock.newCondition();

	//p1、p2共享此方法
	public void setProducer(String name)throws InterruptedException
	{
		lock.lock();//锁
		try
		{
			while(flag)//重复判断标识,确认是否生产
				condition_pro.await();//本方等待

			this.name=name+"......"+count++;//生产
			System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);//打印生产
			flag=true;//控制生产\消费标识
			condition_con.signal();//唤醒对方
		}
		finally
		{
			lock.unlock();//解锁,这个动作一定执行
		}
		
	}

	//c1、c2共享此方法
	public void getConsumer()throws InterruptedException
	{
		lock.lock();
		try
		{
			while(!flag)//重复判断标识,确认是否可以消费
				condition_con.await();

			System.out.println(Thread.currentThread().getName()+".消费."+this.name);//打印消费
			flag=false;//控制生产\消费标识
			condition_pro.signal();
		}
		finally
		{
			lock.unlock();
		}

	}
}

//生产者线程
class Producer implements Runnable 
{
	private Resource res;
	Producer(Resource res)
	{
		this.res=res;
	}
	//复写run方法
	public void run()
	{
		while(true)
		{
			try
			{
				res.setProducer("商品");
			}
			catch (InterruptedException e)
			{
			}
		}
	}
}

//消费者线程
class Consumer implements Runnable
{
	private Resource res;
	Consumer(Resource res)
	{
		this.res=res;
	}
	//复写run
	public void run()
	{
		while(true)
		{
			try
			{
				res.getConsumer();
			}
			catch (InterruptedException e)
			{
			}
		}
	}

}

class  ProducerConsumer
{
	public static void main(String[] args) 
	{
		Resource res=new Resource();

		new Thread(new Producer(res)).start();//第一个生产线程 p1
		new Thread(new Consumer(res)).start();//第一个消费线程 c1

		new Thread(new Producer(res)).start();//第二个生产线程 p2
		new Thread(new Consumer(res)).start();//第二个消费线程 c2
	}
}



                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值