JAVA基础:多线程


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

1.如何在自定义的代码中定义一个线程
 通过对API的查找,Java已经提供了对线程这I类事物描述,Thread类。
创建线程的第一种方式:继承Thread类
步骤:1、定义类继承Thread
   2、复写Thread类中的run方法;
   3、 调用线程的start方法
该方法有两个作用:启动线程,调用run方法:
package thread;

public class Demo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadDemo td= new ThreadDemo();//创建线程
		//d.run();仅仅是对象方法的调用,是单一的线程会先执行run再执行for语句结果不会变化
		td.start();//开启线程,调用run方法
		for(int j=0;j<100;j++)
			System.out.println("main......"+j);
	}

}
class ThreadDemo extends Thread
{
	public void run(){//run方法存储要运行的代码
		for(int i=0;i<100;i++)
		System.out.println("run-------"+i);
	}
}
每一次的运行结果可能有点不同
这是因为多个线程都获取CPU的执行权。CPU执行到谁,谁就运行。明确一点的是,在某一时刻,只能有一个程序在运行(多核CPU除外),CPU在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象的吧多线程的运行行为在互相争抢CPU的执行权。
这就是多线程的一个特性:随机性,谁抢到谁执行,至于执行多长,CPU说的算。

2.为什么要覆盖run方法?
 Thread类描述线程,该类就定义了一个功能,用于存储要运行的代码,该存储功能就是run方法,也就是说Thread类中的run方法,用于存储线程要运行的代码
ThreadDemo th= new ThreadDemo();//创建线程
//th.run(); 仅仅是一个对象的方法调用,是单一的线程,先执行run在执行主线程下面的语句
  th.start();//开启线程,调用run方法
for(int i=0;i<100;i++)
.......

3.普通方法
每个线程都有自己默认的方法
Thread-编号   该编号从0开始
static Thread.currentThread() 获取当前线程对象(相当于this)
getName 获取线程名称
设置线程名称的方法:setName()或构造函数


package thread;

public class ThreadDemo2 {

	/**
	 * 2个线程与主线程交替运行
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo2 d= new Demo2("线程1");
		Demo2 d1= new Demo2("线程2");
		d.start();
//		d.start();出错,IllegalThreadStateException
		d1.start();
		for(int i=0 ;i<100;i++)
			System.out.println("main"+"====="+i);
	}

}
class Demo2 extends Thread{
	//private String name;
	Demo2(String name){
		super(name);
	}
	public void run(){
		for(int i=0;i<100;i++)
		System.out.println((Thread.currentThread()==this)+"..."+this.getName()+"-----"+i);
		//获取当前线程,标准写法:Thread.currentThread()
	}
}

4.创建线程的第二种:实现Runable接口
步骤:
1)定义类实现Runnable接口
2)覆盖Runnable接口中的run方法
将线程运行的代码存放在该run方法中
3)通过Thread类建立线程对象
4) 将Runnable接口的子类对象方法作为实际对象参数传给Thread的构造函数
5)调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
package thread;

public class ThreadTest1 {

	/**
	 * 一个简单的买票引出第二种定义线程的方法
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
/*		Ticket t1= new Ticket();
		Ticket t2= new Ticket();
		Ticket t3= new Ticket();
		Ticket t4= new Ticket();
		t1.start();
		t2.start();
		t3.start();
		t4.start();*/
		//出现第二种创建线程方式,一般推荐使用这种
		Ticket ticket= new Ticket();
		Thread t1= new Thread(ticket);
		Thread t2= new Thread(ticket);
		Thread t3= new Thread(ticket);
			t1.start();
			t2.start();
			t3.start();
	}

}
class Ticket implements Runnable//extends Thread
{
	//private static  int ticket=100 ;//不静态修饰,每new一个线程,都各自卖100张票,实际总共才100张票
	private int ticket=100 ;
	public  void  run(){
		while(true){
			if(ticket>0)
				System.out.println(Thread.currentThread().getName()+"..."+ticket--);
			
		}
	}
}

该创建方式(实现)和继承方式有什么区别
避免了单继承的局限性;

两种创建线程的区别:
继承:线程代码存放于子类的run方法中
实现接口:线程代码存在接口的子类run方法中

6.安全问题
当多条语句在操作通一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据错误。
解决方式:同步代码块
synchronized(对象)
{
需要被同步的代码
}
package thread;
//银行有金库,2个储户各存300员,每次每人存100元
public class ThreadTest2 {
public static void main(String[] args) {
	Cus cus= new Cus();
	Thread t1= new Thread(cus);
	Thread t2= new Thread(cus);
	t1.start();
	t2.start();
}
}
class Bank//查找发现多个线程的共享数据是num
{
	private int num=0;
//	Object obj= new Object();
	public synchronized void add(int money){
		/*synchronized (obj) {
		num=num+money;
		System.out.println(Thread.currentThread().getName()+"num="+num);
		}*/
		num=num+money;
		System.out.println(Thread.currentThread().getName()+"...num="+num);
	}
}
class Cus implements Runnable
{
	private Bank bank= new Bank();
	public void run(){
		for(int i=0;i<3;i++){
			bank.add(100);
		}
	}
}
上述中的对象如同锁,持有锁的线程可以再同步中执行,没有持有锁的线程即使获取CPU的执行权,也进不去,因为没有获取锁。

同步的前提:
1.必须要有两个或两个以上的线程
2.必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行。

好处:解决了多线程的安全问题
弊处:多个线程需要判断锁,较为消耗资源
注意: 非静态同步函数的锁是this而静态同步函数的锁不是this,因为是静态的优先于对象的加载,锁是类名.class
package thread;

public class ThreadTest3 {

	/**
	 * 多线程的懒汉式并发加载的单例模式
	 * @param args
	 */
private static ThreadTest3 s= null;
private ThreadTest3(){}

public static ThreadTest3 getInstance(){
	if(s==null)
		//双重否定稍微提高效率,从第三次开始,判断——不为null直接return,效率提高
	{
		synchronized(ThreadTest3.class)//静态的方法,锁是方法对应的类的字节码文件的对象
		//第二个线程没有锁,必须等第一个执行完
		{
			if(s==null)//第一个线程开始执行有可能停止在这,所以加锁
				s=new ThreadTest3();
		}
	}
	return s;
}

}



利用 TensorFlow 训练自己的目标识别器。本文内容来自于我的毕业设计,基于 TensorFlow 1.15.0,其他 TensorFlow 版本运行可能存在问题。.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值