java8-多线程

本文详细解析Java进程与线程的概念,多线程的特性,以及如何使用Thread类和Runnable接口创建线程。同时,文章深入探讨线程状态、线程安全问题及其解决方案,包括死锁的预防和等待唤醒机制的应用。最后,介绍Java中的守护线程、Join、yield方法以及线程间通讯的基本方法。
摘要由CSDN通过智能技术生成


------- android培训java培训、期待与您交流! ----------

进程:就是一个正在执行中的程序。每个进程都有一个执行顺序,叫一个执行路径,或一个控制单元。
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程中至少有一个线程。


Java VM 启动时会有一个进程java.exe
进程中至少有一个线程在负责程序的执行,并且运行的代码存在于main方法中,称之为主线程。
其实启动时还有个垃圾回收机制的线程。
多线程的特性:随机性,谁抢到执行权,谁执行。


Thread类中的run方法是用于存储要执行的代码,要覆盖。


使用方法:
一:继承Thread类
1,定义类继承Thread.
2,复写Thread类中的run方法
目的为了把自定义的代码存储到run方法中,并让线程运行。
3,调用线程的start方法。作用(启动线程,调用run方法)。


二:创建线程的第二种方式,实现Runnable接口。
步骤:
1,定义类实现Runnable接口
2,覆盖Runnable接口中的run方法(将线程要运行的代码存放在该run方法中)
3,通过Thread类建立线程对象
4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数(因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run方法,必须要明确该run方法所属的对象)
5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法


继承和实现的区别
实现方式避免了单继承的局限性,建议使用实现方式。
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable,线程代码存放在接口子类的run方法中。


 线程的4种状态


创建 start() 运行 sleep(time)时间到会自动运行;wait()等待notify()唤醒
冻结(睡眠和等待两种)
消亡 stop();或run方法结束。


特殊状态 :临时状态,阻塞 有运行资格CPU没有给执行权。冻结没有运行资格,结束冻结会先回到临时状态。


多线程中,由于阻塞状态,多条语句操作同一个线程共享数据时,可能一个线程正在执行时产生阻塞,另一个线程也参与执行。导致出现安全隐患。


如何找到安全隐患
1,明确多线程运行的代码。
2,明确共享数据。
3,明确多线程运行代码中哪些语句是操作共享数据的。


解决办法是,对多线程执行共享数据的语句,只能让一个线程执行完。过程中不准别的参与。加锁。
Java提供了专业解决方式。
就是同步代码块
同步函数
函数要被对象调用,就会有个所属对象引用,就是this,锁是 this.
静态同步函数被类调用,直接属于类,锁是 类名.class,类型是Class。
synchronized做为修饰符。
修饰符 修饰符 返回值类型 函数名()


死锁
同步中嵌套同步,用的锁不相同,就会产生死锁。


synchronized(对象)//相当于一次只能完全执行一个线程,过程中不能执行其他线程。
{
需要被同步的代码
}


前提:
1,必须要有两个或者多个以上的线程。
2,必须是多个线程使用同一个共享数据。
必须保证共同使用的共享数据要同步,就是只执行一个线程。


解决了多线程的安全问题,但是由于需要判断,较消耗资源。


static Thread curretThread():获取当前线程对象。
getName():获取线程名称。
setName或者是构造函数可以用来设置线程名称。


class Demo extends Thread//继承Thread
{
	//复写Thread类中的run方法
	public void run()
	{
		//自定义要线程运行的代码
		for(int x=1;x<10;x++)
			System.out.println("Demo run_"+x);
	}
}

class ThreadDemo
{
	public static void main(String[] args)
	{
	
		Demo d = new Demo();//创建好一个线程d.
		//d.start();//开启d线程,并且执行其中的run方法。
		d.run();//只是调用了run方法,线程却没有运行,只创建了。
		
		for(int x=1;x<10;x++)
			System.out.println("main run_"+x);
	}
}

//卖票程序:多个窗口买票

class Ticket implements Runnable//实现Runnable接口	同步代码块
{
	private int tick = 100;
	Object obj = new Object();
	public void run()//将线程要运行的代码存放在该run方法中
	{
		while(true)
		{	

			synchronized(obj)//同步代码块
			{
				//多线程执行共享数据的语句
				if(tick>0)//由于临时状态,阻塞,多线程可能出现安全隐患

				{	
					System.out.println(Thread.currentThread().getName()+"..."+ tick--);
				}
			}
		}
	}
}

class Ticket implements Runnable//实现Runnable接口	同步函数
{
	private int tick = 100;

	public void run()
	{
		while(true)
		{	
			this.show();

		}
	}
	//由于临时状态,阻塞,多线程可能出现安全隐患
	public synchronized void show()//同步函数synchronized(this)
	{
		if(tick>0)
		{	

			System.out.println(Thread.currentThread().getName()+"..."+ tick--);
		}
	}
}

class TicketDemo
{
	public static void main(String[] args)
	{
		Ticket t = new Ticket();//建立Runnable接口的子类对象
		Thread t1 = new Thread(t);//Thread类建立线程对象,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);	
		t1.start();//调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
		t2.start();
		t3.start();	
	}
}


等待唤醒机制
wait();线程等待
notify();唤醒其他线程
notifyAll();唤醒全部线程


都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要用在同步中,只有同步才有锁。


因为这些方法在操作同步线程时,都必须要标识它们所操作的线程共有的锁,只有同一锁上的被等待线程,可以被同一个锁上notify唤醒。不同锁的线程不能进行唤醒。就是只能于相同锁上才有效。
锁可以是任意对象,因此能被任意对象调用的方法只能定义在Object类中。


if()notify()用于一对一线程。用于多对多时可能会覆盖
while()notifyAll()用于多对多线程。while不用All会全部冻结。


JDK1.5中提供了多线程升级解决方案。将同步Synchronized替换成实现Lock操作。将Object中的wait,notify notifyAll,替换成了Condition对象,该对象可以Lock锁,进行获取。
可以唤醒不同锁。相当于父类引用指向子类对象,多态的方法调用一样。能够唤醒指定的锁。


停止线程
stop方法过时,只能run方法结束。
开启多线程运行,运行代码通常是循环结构。控制住循环,就能让run结束,关闭线程。
当线程处于冻结状态时,不会读到结束,不会结束线程。
没有指定方式让冻结的线程恢复到运行状态时,需要清除冻结状态,强制让线程恢复到运行状态中,就可以操作线程让线程结束。
Thread类中提供了interrupt();方法。


守护线程
setDaemon
public final void setDaemon(boolean on)
t1.setDaemon(true);
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。就是守护线程不能独立运行。


Join
public final void join()
                throws InterruptedException
等待该线程终止。 
就是借用正在执行线程的执行权,结束了才交还执行线程。
用于临时加入线程。


yield
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。 
相当于放弃下执行权,不长期占用。


toString
public String toString()返回该线程的字符串表示形式,包括线程名称、优先级和线程组。一般谁开的线程就属于哪个组。
setPriority
public final void setPriority(int newPriority)更改线程的优先级。 (1到10分为1,5,10三等)

线程间通讯
多个线程操作同一个资源,操作动作不同(输入输出)。


class Res//要共用的资源
{
	private String name;
	private String sex;
	private boolean flag = false;//用来改变线程状态
	public synchronized void set(String name,String sex)
	{
		if(flag)	//b函数上锁是this
			try{this.wait();}catch(Exception e){}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();
	}
	public synchronized void out()
	{
		if(!flag)
			try{this.wait();}catch(Exception e){}
			//wait()有异常,实现接口中只能try
		System.out.println(name+"---"+sex);
		flag = false;
		this.notify();//唤醒线程
	}
}
//输入操作线程
class Input implements Runnable
{
	private Res r;
	Input(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0;//定义输入值
		while(true)
		{
			if(x==0)
				r.set("mini","man");
			else
				r.set("一一","女");
			x = (x+1)%2;
		}
	}
}
//输出操作线程
class Output implements Runnable
{
	private Res r;
	Output(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}

class InputOutputDemo
{
	public static void main(String[] args)
	{
		//建立共用操作对象
		Res r = new Res();
		//使用匿名对象开启线程
		new Thread(new Input(r)).start();
		new Thread(new Output(r)).start();
	}
}

-------  android培训 java培训 、期待与您交流! ----------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值