线程

1、线程的定义
单道程序设计:计算机中除了操作系统之外,只存在一个用户程序,即用户独享整个计算机的资源
特点:资源独占性:任何时候,位于内存中的程序可以使用系统中的一切资源,不可能有其他程序的竞争;执行的顺序性:内存中每次只有一个程序,各个程序按次序执行;结果的再现性:只要执行环境和初始条件相同,重复执行一个程序结果都一样。
多道程序设计::计算机中除了操作系统之外,存在多个用户程序,这些程序同时运行。
特点:间断性,因为资源的共享和合作,并发程序之间相互制约,造成合作执行的间断;失去封闭性:程序执行受外界影响;不可再现性:程序重复执行可能得不到相同的结果(同一时刻运行程序多)。
进程:一次运行一个程序,程序即程序的运行。现在程序将不能模拟程序的运行。一个程序被三个程序同时运行加载,一个程序产生三个进程。用进程来模拟加载数据之后的一次运行。
线程: 是一个程序里的不同执行路径,单个程序内部是可以在同一时刻进行多种运算的.

    (1)什么是进程?为什么需要进程?
    (2)**什么是线程?**为什么需要线程?(进程之间的切换需要花时间,耗时)
    多线程优势:编程简单,效率高,适合于开发服务
class A extends Thread
{
	public void run()
	{   while(true){
		System.out.println("AAAA");		
		}
 }
}
public class TestThread_2
{
	public static void main(String[] args)
	{
	         	A aa = new A();		
                aa.start(); //不同于run();start()开启一个新线程,上面必须含run()方法执行“AAA”,交替同时执行下面的代码,在某个结点分支,多代码交替的占用cpu,会自动调用run方法aa.run()只有“AAA”执行
		      System.out.println("BBBB");
	}
}

运行结果:
在这里插入图片描述
2、线程的创建
第一种方式创建:
在这里插入图片描述

注意:一个线程只能执行run方法中的代码

在这里插入图片描述

线程状态的切换

在这里插入图片描述

一个thread对象不能调用两次start()

在这里插入图片描述
不能两次调用start()

package java_part;

class ThreadA extends Thread
{
	public void run()
	{
		System.out.println("AAAA"); 
	/*
		while (true)                  //第二个aa.start()没有被执行到,一直输出是AAA
		{
			System.out.println("AAAA");
		}	
		*/		
	}
	
}

public class TestThread_1
{
	public static void main(String[] args)
	{
		ThreadA aa = new ThreadA();
		aa.start(); //aa.start(); 会自动调用run方法
		aa.start();//
		//aa.start();
		while (true)
		{
			System.out.println("BBBB");
		}
	}
}

在这里插入图片描述
第二种创建方式
利用接口实现

class ThreadB implements Runnable{
	public void run() {
		while(true) {
			System.out.println("AAA\n");
		}
	}	
}
public class TestThread_2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadB  bb=new ThreadB();
		Thread t=new Thread(bb);
		t.start();
		while(true) {
			System.out.println("BBB\n");
		}
				
		//里面没有start()方法bb.start();
	}
}

Thread中的常用方法
public final void setName(String name)
设置当前线程的名字
public static Thread currentThread()
返回当前正在执行的线程对象的引用
public final String getName()
返回当前线程的名字

class ThreadC extends Thread{
	public void run() {
	  System.out.println("AAA\n");	
	  System.out.printf("%s在执行\n",Thread.currentThread().getName());
	}	
	
}
public class ThreadFun {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadC cc1=new ThreadC();
		cc1.start();
		cc1.setName("What");
		ThreadC cc2=new ThreadC();
		cc2.start();
		cc2.setName("How");
		ThreadC cc3=new ThreadC();
		cc3.start();
		System.out.println("CCCC\n");
		System.out.printf("%s在执行\n",Thread.currentThread().getName());//Thread.currentThread()返回当前对象的引用
	}

}

实验结果:
在这里插入图片描述
3、线程的控制
(1)方法如下
Thread.sleep()将当前线程睡眠。阻塞,下一时刻不能立即运行,需要进入就绪状态
join():等待该线程结束,再回复当前线程的运行
yield():(本来在运行)让出cpu,当前线程进入就绪队列等待调度,下一时刻可以立即运行;
wait();
notify();
(2)线程的优先级1-10,默认为5,
(3)线程的休眠–暂停当前运行中的线程,使之进入阻塞状态。待经过指定的“延迟时间”后再醒来并转入就绪状态
在这里插入图片描述
Thread.sleep()
一般利用Thread.sleep()放置run()方法,对当前线程进行暂停。同时,无论是继承Thread类的run方法还是实现Runnable接口的run方法,都不能抛出异常。


public class TestSleep_3
{
	public static void main(String[] args)
	{
		SleepA  aa = new SleepA ();
		Thread tt = new Thread(aa);
		tt.start();	
		for (int i = 0; i < 3; i++) {
			System.out.println("main thread :"+i);
		}	
	}
}
class SleepA  implements Runnable
{
	public void run() //throws Exception
	{ //9行	
		for (int i=0; i<10; ++i)
		{
			System.out.println(Thread.currentThread().getName() + "   " + i);			
			try
			{
 			   Thread.sleep(1000);  //让线程暂停 1s                                                   
			}catch (Exception e)
			{  
			}
			//Thread.sleep(1000);	
			System.out.println("哈哈哈哈哈哈哈哈哈");
		}
	}
}

结果输出为
在这里插入图片描述
一直到输出为Thread-0 9
哈哈哈哈哈哈哈哈
有时也会输出:开启的Thread0线程在暂停1s中进入阻塞状态,可能不会立即执行,主要是cpu控制。
在这里插入图片描述
Thread.yield()线程的让步
让出cpu,给其他线程执行的机会
让运行中的线程主动放弃当前获得的cpu处理机会。但不是使该线程阻塞,而是使之转入就绪状态。public static void yield()注意:
使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了
Thread.join()
需要原因:在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。在哪个线程A中调用另一个线程B.join(),就需要等待B线程结束之后,再执行A线程。

public class TestJoin {	
	public static void main(String args[]){
		MyRunner r = new MyRunner();
		Thread t = new Thread(r);
		t.start();
		try{
			t.join(); //7行  暂停当前正在执行t.join();的线程,直到t所对应的线程运行终止之后,当前线程才会获得继续执行的机会
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		for(int i=0;i<50;i++){
			System.out.println("主线程:" + i);
		}
    }
}

class MyRunner implements Runnable {
	public void run() {
		for(int i=0;i<50;i++) {
			System.out.println("子线程: " + i);
		}
	}
}

结果输出:
在这里插入图片描述
什么是死锁:两个线程彼此都需要对方资源进行运行,但双方都不想让,程序无法运行。
4、线程的同步
A买票
同步:synchronized这个关键字,将任务锁起来,当某个线程进来时,不能让其他线程继续进来,那就代表是同步了。A线程在执行时,另一个线程不能执行。直到执行完其他线程才可以执行。
同一个站点共同对100张票卖,多个线程对同一段关键程序资源进行操作。
synchronized修饰一个方法或者一个方法内部代码
重点:synchronized修饰代码块,
synchronize(类对象名aa)//判断aa是否已被其他线程霸占,若被其他线程霸占,当前线程陷入等待,否则当前占用,指向同步代码块,其他线程没有可能再执行。当前线程执行我那同步代码块之后释放对aa对象的霸占,此时,其他线程会相互经常对aa的霸占,最终cpu选择其中一个线程执行。
{
同步代码块
}

(1)利用实现接口方法,以及synchronized(str){},public int tickets,因为使用相同的对象,变量ticket和String不需要设置静态变量

public class TestSyn
{
	public static void main(String[] args) throws Exception
	{
		SynA aa = new SynA();
		Thread t1 = new Thread(aa);
		Thread t2 = new Thread(aa);
		t1.start();
		t2.start();
	}
}

class SynA implements Runnable
{
	public int tickets = 100;
	String str = new String("123");
	public void run()
	{		//String str = new String("123");将不是锁定同一个对象
	      while (true)
			{synchronized (str) {
				if (tickets > 0)
				{
					  System.out.printf("%s线程正在卖出第%d张票!\n", 
								Thread.currentThread().getName(), tickets);
					--tickets;
				}
				else
				{
					break;
				}			
			}
		}
	}
}

在这里插入图片描述

对于容易出错的利用synchronized(this)

public class TestSync3
{
	public static void main(String[] args)
	{
		ThreadRun tr = new ThreadRun();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();
	}
}

class ThreadRun implements Runnable
{
	private int tickets = 100;
	
	public void run()    
	{
 		synchronized (this)
 		{
			while (true)  
			{
				if (tickets > 0)
				{
					System.out.printf("%s线程正在卖出第%d张票!\n", 
								Thread.currentThread().getName(), tickets);
					--tickets;			
				}
				else
				{
					break;
				}
			}
		}
	}
}

2、利用继承extends实现同步
/ok注意用生成不同的对象,保证变量为静态,锁定同一个对象。

class A extends Thread
{
	public static int tickets = 100;  //static不能省
	public static String str = new String("哈哈");  //static不能省
		
	public void run()
	{
		while (true)
		{
			synchronized (str)
			{
				if (tickets > 0)
				{
					System.out.printf("%s线程正在卖出第%d张票\n",
						Thread.currentThread().getName(), tickets);
					--tickets;	
				}
				else
				{
					break;
				}
			}
		}
	}
}

public class TestTickets_3
{
	public static void main(String[] args)
	{
		A aa1 = new A();
		aa1.start();	
			
		A aa2 = new A();
		aa2.start();		
	}
}

3利用synchronized修饰函数

class Thd2 implements Runnable
{
	private int tickets = 100;
	
	public synchronized void run()   
	{
		while (true) 
		{
			if (tickets > 0)
			{
				System.out.printf("%s线程正在卖出第%d张票!\n", 
							Thread.currentThread().getName(), tickets);
				--tickets;
			}
			else
			{
				break;
			}
		}
	}	
}
public class TestSync
{
	public static void main(String[] args)
	{
		Thd2 tr = new Thd2();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();
		new Thread(tr).start();		
	}
}

B生产消费
(1)
this.notify:不是叫醒正在执行this.notify()的当前线程,而是叫醒一个现在wait this对象的其他线程,(若另外线程因为执行this.wait阻塞的线程)如果多个线程正在wait this对象,通常叫醒最先wait this对象的线程,但具体叫醒哪一个通常由系统调度器控制,程序员无法控制。所谓叫醒就是令该线程性因为wait陷入阻塞转入就绪状态。
this.wait线程暂停:将执行this.wait()当前线程转入阻塞状态,释放对对象的锁定。
对象.notifyAll()叫醒其他所有因为执行对象.wait()而陷入阻塞状态的线程。
《经典消费问题》仓库最多容纳6个产品,制造商要制造10件产品放入仓库,消费者从仓库中取出20件产品来消费。制造商制造商品和消费者取出产品的速度可能不一样。

public class SyncTest
{
    public static void main(String args[]) throws Exception
    {
		SyncStack stack = new SyncStack();
		Runnable p=new Producer(stack);
		Runnable c = new Consumer(stack);
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(c);
		t1.start();
		
		Thread.sleep(1000);
		
		t2.start();
		
//		Thread t3 = new Thread(p);
//		t3.start();
//		Thread t4 = new Thread(c);
//		t4.start();
    }
}
class SyncStack{  //支持多线程同步操作的堆栈的实现
	private int index = 0;
	private char []data = new char[6];	
	
	public synchronized void push(char c)
	{
		while(index == data.length)//满了,暂停
		{  
			try
			{
				this.wait();  //暂停
			}catch(InterruptedException e)
			{
				e.printStackTrace();
				System.exit(-1);
			}
		}
		this.notify();
		data[index] = c;
		index++;
		System.out.println("生产: "+c);
		System.out.printf("容器里有%d个字母\n\n", index);
	}
	
	public synchronized char pop()
	{
		while(index == 0)
		{
			try
			{
				this.wait();
			}
			catch(InterruptedException e)
			{
				e.printStackTrace();
				System.exit(-1);
			}
		}

		this.notify();
		index--;
		System.out.println("取出:"+data[index]);
		System.out.printf("容器里还有%d个字母!\n\n", index);
		return data[index];
	}
}


class  Producer implements Runnable
{
	SyncStack stack;	
	public Producer(SyncStack s)
	{
		stack = s;
	}
	
	public void run()
	{
		for(int i=0; i<20; i++)
		{
			char c =(char)('a'+i);
			stack.push(c);
			try
			{							        
				Thread.sleep((int)(Math.random()*20));
			}catch(InterruptedException e)
			{
			}
		}
	}
}

class Consumer implements Runnable
{
	SyncStack stack;	
	public Consumer(SyncStack s)
	{
		stack = s;
	}
	
	public void run()
	{
		for(int i=0;i<20;i++)
		{
			char c = stack.pop();
			try
			{							           
				Thread.sleep((int)(Math.random()*1000));
			}
			catch(InterruptedException e)
			{
			}
		}
	}
}

实验结果

生产线程正在生产第1个产品,该产品是: a
生产线程正在生产第2个产品,该产品是: b
生产线程正在生产第3个产品,该产品是: c
生产线程正在生产第4个产品,该产品是: d
生产线程正在生产第5个产品,该产品是: e
生产线程正在生产第6个产品,该产品是: f
消费线程正在消费第6个产品,该产品是: f
生产线程正在生产第6个产品,该产品是: g
消费线程正在消费第6个产品,该产品是: g
生产线程正在生产第6个产品,该产品是: h
消费线程正在消费第6个产品,该产品是: h
生产线程正在生产第6个产品,该产品是: i
消费线程正在消费第6个产品,该产品是: i
生产线程正在生产第6个产品,该产品是: j
消费线程正在消费第6个产品,该产品是: j
生产线程正在生产第6个产品,该产品是: k
消费线程正在消费第6个产品,该产品是: k
生产线程正在生产第6个产品,该产品是: l
消费线程正在消费第6个产品,该产品是: l
生产线程正在生产第6个产品,该产品是: m
消费线程正在消费第6个产品,该产品是: m
生产线程正在生产第6个产品,该产品是: n
消费线程正在消费第6个产品,该产品是: n
生产线程正在生产第6个产品,该产品是: o
消费线程正在消费第6个产品,该产品是: o
生产线程正在生产第6个产品,该产品是: p
消费线程正在消费第6个产品,该产品是: p
生产线程正在生产第6个产品,该产品是: q
消费线程正在消费第6个产品,该产品是: q
生产线程正在生产第6个产品,该产品是: r
消费线程正在消费第6个产品,该产品是: r
生产线程正在生产第6个产品,该产品是: s
消费线程正在消费第6个产品,该产品是: s
生产线程正在生产第6个产品,该产品是: t
消费线程正在消费第6个产品,该产品是: t
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值