黑马程序员--多线程

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

一、多线程概述

进程:指一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序就是一个执行路径,或者叫一个控制单元。

线程:是进程中的一个独立的控制单元,控制着进程的执行。

注意:一个进程中至少有一个线程,且多线程有随机的特性。

如javaVM启动的时候,就会有一个进程java.exe。该进程中有两个线程参与运行,一个是代码存在于 main方法中的主线程,还有一个是jvm启动时的一个负责垃圾回收机制的线程。

定义线程的方法:

1,继承Thread类并复写run()方法,然后调用线程的start方法。

start方法:启动线程,并调用run方法。

注意:千万别再主函数中调用run方法,那样会导致自始至终都是主线程在执行。

2,定义类实现Runnable接口,覆盖Runnable接口中的run方法。通过Thread类建立线程对象,将Runnable接口的子类对象传递给Thread类的构造函数。调用Thread类的start方法开启线程并调用Runnable接口的子类run方法。

线程有自己的名称,为Thread-编号。

获取当前线程对象:static Thread currentThread()

获取线程名称:getName()

设置线程名称:setName或者super(name);

实现方式避免了单继承的局限性,所以定义线程时,应用实现方式完成。

package 博客5_多线程;
class Text extends Thread//创建一个类继承Thread
{
	private String name;
	Text(String name)
	{
		this.name=name;
	}
	public void run()//复写Thread类的run方法
	{
		for(int x = 0 ;x < 60;x++)
		{
			System.out.println(name+"...run..."+x);
		}
	}
}
public class 创建线程_继承方式 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Text t1 = new Text("one");//创建Text对象
		Text t2 = new Text("two");
		t1.start();//开启线程。
		t2.start();
	}

}

package 博客5_多线程;

class Text_2 implements Runnable//定义类实现Runnable接口
{
	private String name;
	Text_2(String name)
	{
		this.name = name;
	}
	public void run()
	{
		for(int x = 0;x<60;x++)
		{
			System.out.println(Thread.currentThread().getName()+".....run...."+x);
		}
	}
	
}

public class 创建线程_实现方式 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Text_2 t = new Text_2("一号");//创建子类对象
		Thread t1 = new Thread(t);//创建线程
		Thread t2 = new Thread(t);
		t1.start();//启动线程
		t2.start();
	}

}
二、线程的安全问题
多线程运行时出现安全问题的原因:当多条语句在操作同意线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完另一个线程参与进来执行,导致共享数据错误。

解决方法:对多条操作共享数据的语句,只能让一个线程执行完,且在执行过程中,其他线程不可以参与执行即可。

java对于多线程的安全问题提供了专业的解决方式:同步代码块。

同步代码块格式:synchronized(对象)

{

需要被同步的代码;

}

package 博客5_多线程;

class Ticket implements Runnable
{
	private int tick = 100 ;
	Object obj = new Object();
	public void run()//复写Runnable中的run方法
	{
		while(true)
		{
			synchronized(obj)//加一把Object对象的锁
			{
				if(tick>0)
					System.out.println(Thread.currentThread().getName()+"...sale...."+tick--);
			}
		}
	}
}

public class 同步代码块_卖票小程序synchronized {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ticket t = new Ticket();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
		Thread t4 = new Thread(t);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}
同步的前提:

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

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

同步的目的:保证同步中只有一个线程在运行。
同步的优点:解决了多线程的安全问题。

同步的缺点:效率较低。

获取多线程安全问题的步骤:

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

2,明确共享数据。

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

同步函数:可以将synchronized作为修饰符放在函数上即可。

同步函数的锁是this,因为同步函数都有一个所属对象的引用。

如果同步函数被静态修饰的时候,用的锁是Class对象。

因为静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象,该对象就是类名.Class。该对象的类型是Class。

死锁:同步中嵌套同步,但是用的不是同一把锁。如同步代码块中嵌套同步函数,同步函数中嵌套同步代码块。

package 博客5_多线程;

class MyLock//自己定义一个锁
{
	static Object locka = new Object();
	static Object lockb = new Object();
}

class DeadLockText implements Runnable
{
	private boolean flag;//设置一个标记,让两个线程可以交替运行
	DeadLockText(boolean flag)
	{
		this.flag=flag;
	}
	public void run()
	{
		if(flag)
		{
			/*
			 * 创造一种死锁的情况
			 * */
			synchronized(MyLock.locka)
			{
				System.out.println("if Locka");
				synchronized(MyLock.lockb)
				{
					System.out.println("if Lockb");
				}
			}
		}
		else
		{
			synchronized(MyLock.lockb)
			{
				System.out.println("else Lockb");
				synchronized(MyLock.locka)
				{
					System.out.println("else Locka");
				}
			}
		}
	}
}
public class 死锁Text {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t1 = new Thread(new DeadLockText(true));
		Thread t2 = new Thread(new DeadLockText(false));
		t1.start();
		t2.start();
	}

}
三、线程间通信
线程间通信:多个线程在操作同一个资源,但是操作的动作不同。

线程间通信保证安全问题的方法:

1,加锁,保证线程同步。

2,通过等待唤醒机制。

package 博客5_多线程;
/*
 * 用加锁的方式完成线程间通信的安全问题
 * */
class Res//创建一个资源对象
{
	String name;
	String sex;
}
class Input implements Runnable//输入名字和性别的对象
{
	private Res r;//保证对象唯一,也可以用单例,但是没有这样简单
	Input(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0 ;
		while(true)
		{
			synchronized(r)//需要加锁,保证线程同步。r是唯一对象,可以保证使用的是同一把锁。
			{
				if(x==0)
				{
					r.name="mike";
					r.sex="man";
				}
				else
				{
					r.name= "丽丽";
					r.sex="女";
				}
				x=(x+1)%2;
			}
		}
	}
}
class Output implements Runnable
{
	private Res r;
	Output(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			synchronized(r)
			{
				System.out.println(r.name+"......"+r.sex);
			}
		}
	}
}

public class 线程间通信 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Res r = new Res();
		Input in = new Input(r);
		Output op = new Output(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(op);
		t1.start();
		t2.start();
	}

}
线程池:用于存放等待的线程。唤醒的时候要唤醒先等待的线程。
wait,notify,notifyAll都使用在同步中,因为要对持有监视器(锁)的线程操作,所以只能定义在同步中。

注意:等待和唤醒的必须是使用同一把锁。

上述代码优化后的结果为:

package 博客5_多线程;
class Res_1//创建一个资源对象
{
	private String name;
	private String sex;
	private boolean flag=false;//定义标记,初始化为假
	public synchronized void set(String name,String sex)//同步函数,锁是this
	{
		if(flag)//如果为真,则等待,但是由于flag初始化为假,所以可以执行下面的语句
			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){}
		System.out.println(name+"....."+sex);
		flag = false;
		this.notify();
	}
}
class Input_1 implements Runnable//输入名字和性别的对象
{
	private Res_1 r;//保证对象唯一,也可以用单例,但是没有这样简单
	Input_1(Res_1 r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0 ;
		while(true)
		{
			if(x==0)
				r.set("mike","man");
			else
				r.set("丽丽","女");
				x=(x+1)%2;
		}
	}
}
class Output_1 implements Runnable
{
	private Res_1 r;
	Output_1(Res_1 r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();
		}
	}
}

public class 线程间通信_等待唤醒机制
{
	public static void main(String[] args)
	{
		Res_1 r = new Res_1();
		new Thread(new Input_1(r)).start();
		new Thread(new Output_1(r)).start();
	}
}
当多个线程同时进行通信时,上述代码的if应更换成while,同时notify应更改成notifAll。

换成while是为了让被唤醒的线程再一次判断标记,但是如果不改notify,则会造成所有线程都等待的情况。所以应将notify更改成notifyAll。

四、多线程的其他操作

1,停止线程。

原理:想停止线程,就要让run方法结束。因为开启多线程的时候,运行代码通常都是循环结构,所以只要控制住循环,就可以让run方法结束,也就是线程结束。

特殊情况:当线程处于冻结状态时,就无法读取到循环结束标记,那么线程就不会结束。

当没有指定的方式让冻结的线程恢复到运行状态时,就需要对冻结进行清除。强制的让线程恢复到运行状态,这样就可以通过操作标记让线程结束。

用Thread类中提供的方法interrupt。

2,守护线程

Thread类中的setDeamon方法。需要在线程开启前调用。

当线程被标记为守护线程后,当正在运行的线程都是守护线程时,java虚拟机会自动退出,结束线程。

3,Join方法

当主线程执行到线程的join方法时,就会释放自己的执行权给调用join方法的线程,等他先执行完之后才会继续执行。

4,yield方法

线程的优先级是从1到10个等级。默认的优先级都是5。

通过setPriority可以设置优先级。

yield方法,暂停当前正在执行的线程对象,并执行其他线程。






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数字乡村和智慧农业的数字化转型是当前农业发展的新趋势,旨在通过应用数字技术,实现农业全流程的再造和全生命周期的管理服务。中国政府高度重视这一领域的发展,提出“数字中国”和“乡村振兴”战略,以提升国家治理能力,推动城乡融合发展。 数字乡村的建设面临乡村治理、基础设施、产业链条和公共服务等方面的问题,需要分阶段实施《数字乡村发展战略纲要》来解决。农业数字化转型的需求包括满足市民对优质农产品的需求、解决产销对接问题、形成优质优价机制、提高农业劳动力素质、打破信息孤岛、提高农业政策服务的精准度和有效性,以及解决农业融资难的问题。 数字乡村建设的关键在于构建“1+3+4+1”工程,即以新技术、新要素、新商业、新农民、新文化、新农村为核心,推进数据融合,强化农业大数据的汇集功能。数字农业大数据解决方案以农业数字底图和数据资源为基础,通过可视化监管,实现区域农业的全面数字化管理。 数字农业大数据架构基于大数据、区块链、GIS和物联网技术,构建农业大数据中心、农业物联网平台和农村综合服务指挥决策平台三大基础平台。农业大数据中心汇聚各类涉农信息资源和业务数据,支持大数据应用。信息采集系统覆盖市、县、乡、村多级,形成高效的农业大数据信息采集体系。 农业物联网平台包括环境监测系统、视频监控系统、预警预报系统和智能控制系统,通过收集和监测数据,实现对农业环境和生产过程的智能化管理。综合服务指挥决策平台利用数据分析和GIS技术,为农业决策提供支持。 数字乡村建设包括三大服务平台:治理服务平台、民生服务平台和产业服务平台。治理服务平台通过大数据和AI技术,实现乡村治理的数字化;民生服务平台利用互联网技术,提供各类民生服务;产业服务平台融合政企关系,支持农业产业发展。 数字乡村的应用场景广泛,包括农业生产过程、农产品流通、农业管理和农村社会服务。农业生产管理系统利用AIoT技术,实现农业生产的标准化和智能化。农产品智慧流通管理系统和溯源管理系统提高流通效率和产品追溯能力。智慧农业管理通过互联网+农业,提升农业管理的科学性和效率。农村社会服务则通过数字化手段,提高农村地区的公共服务水平。 总体而言,数字乡村和智慧农业的建设,不仅能够提升农业生产效率和管理水平,还能够促进农村地区的社会经济发展,实现城乡融合发展,是推动中国农业现代化的重要途径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值