Java之线程

线程
首先需要了解,什么是线程?
线程不是进程,但其行为很像进程,线程是比进程更小的执行单位,一个进程在其执行的过程中,可以产生多个线程。线程是程序执行的一条路径,一个进程可以包含多条线程。多线程并发执行可以提高程序的效率,可以同时完成多项工作。

线程的生命周期
1、新建:新创建一个线程对象。
2、可运行:线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获得cpu的使用权。
3、运行:可运行状态的线程获得了cpu时间片(timeslice),执行程序代码。
4、阻塞:阻塞状态是指线程因为某种原因放弃了cpu的使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行状态,才有机会再次获得cpu timeslice转到运行状态。阻塞的情况分为三种:等待阻塞、同步阻塞、其他阻塞。
5、死亡:线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次重生。

多线程并行和并发的区别
多线程并发可以提高程序的效率,那么并行和并发的区别是什么?
并行是两个任务同时运行,在A任务执行的同时,B任务也在执行(需要多核CPU)。
并发是指多个任务都请求运行,而处理器只能接受一个任务,把多个任务安排轮流执行,由于时间间隔较短,让人感觉多个任务在同时运行。

实现多线程的两种方法
一、继承Thread:定义类继承Thread;重写run方法;把新线程做的事写在run()方法中;创建线程对象;开启新线程,自动执行run()方法。

package com.hpu.edu.dong;

public class dong {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		MyThread mt=new MyThread();
		mt.start();     
		for (int i = 0; i < 10; i++) {
			System.out.println("2");
		}
	}
}
class MyThread extends Thread{//继承Thread
	@Override			
	public void run() {			//重写run方法
		// TODO Auto-generated method stub
		for (int i = 0; i < 5; i++) {
			System.out.println("1");
		}
	}
}


二、实现Runnable接口
定义类实现Runnable接口;实现run方法;把新线程做的事写在run方法中;创建自定义的Runnable的子类对象;创建Thread对象,传入Runnable;调用start()开启新线程,内部会自动调用Runnable的run()方法。

package com.hpu.edu.dong;

public class dong {

	public static void main(String[] args){
		// TODO Auto-generated method stub
		MyRunnable mr=new MyRunnable();//创建Runnable的子类对象
		Thread t=new Thread(mr);		//将其当作参数传递给Thread的构造函数
		t.start();						//开启线程
		for (int i = 0; i < 8; i++) {
			System.out.println("2");
		}
	}
}
class MyRunnable implements Runnable{//定义一个类实现Runnable

	@Override
	public void run() {//重写run方法
		// TODO Auto-generated method stub
		for (int i = 0; i < 5; i++) {//写入要执行的代码
			System.out.println("1");
		}
	}
	
}

两种方法的区别
区别:
继承Thread:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()方法。
实现Runnable:构造函数中传入了Runnable的引用,start()调用run()方法时内部判断成员变量Runnable()的引用是否为空,不为空编译时看的是Runnable()的run(),运行时执行的是子类的run()方法。
继承Thread:
好处:可以直接使用Thread类中的方法,代码简单;
弊端:如果已经有了父类,就不能使用这种方法。
实现Runnable接口
好处:定义的线程有父类也没影响,因为有了父类也可以实现接口,而且接口是多实现的。
弊端:不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂。

同步代码块
首先先了解什么是同步?假设有两段代码块,在同一时间只能执行一段,在这段代码块没执行结束之前,不会执行另外一段代码块。
什么情况下需要同步?当多线程并发,有多段代码同时执行时,我们希望某一段代码执行的过程中cpu不要切换到其他线程工作,这时就需要同步。
同步代码块的使用需要用到关键字:synchronized。

package com.hpu.edu.dong;

public class dong {

	public static void main(String[] args){
		// TODO Auto-generated method stub
		final weapon wp=new weapon();
		new Thread(){
			public void run() {
				while(true){
					wp.print1();
				}
			}
		}.start();
		new Thread(){
			public void run() {
				while(true){
					wp.print2();
				}
			}
		}.start();
	}
}
class weapon{
	syn s=new syn();
	public void print1(){
		synchronized (s) {
			System.out.print("圣");
			System.out.print("耀");
			System.out.print("救");
			System.out.print("赎");
			System.out.print("\r\n");
		}
	}
	public void print2(){
		synchronized(s){
			System.out.print("苍");
			System.out.print("穹");
			System.out.print("幕");
			System.out.print("落");
			System.out.print("\r\n");
		}
		
	}
}
class syn{
	
}

死锁
死锁定义:多个进程在执行的过程中,因争夺同类资源且资源分配不当而造成的一中互相等待的现象。若无外力作用,它们都将永远无法继续执行,这种状态称为死锁,这些处于等待状态的进程称为死锁进程。
死锁出现的条件:一、必须是两个或者两个以上进程(线程);二、必须有竞争资源。
例子:假设线程1在执行的时候占用了资源1,此时,需要占用资源2才能继续执行,同时线程2使用了资源2,需要占用资源1才能继续执行:

package com.hpu.edu.dong;

public class dong1 {
	
	private static String s1="线程1";
	private static String s2="线程2";
	private static String R1="资源1";
	private static String R2="资源2";

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				
					while(true){
						synchronized (s1) {
							System.out.println(getName()+s1+"使用"+R1+"请求"+R2);
							synchronized(s2){
								System.out.println(getName()+"获取"+R2+"执行");
							}
					}
				}
			}
		}.start();
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				
					while(true){
						synchronized (s2) {
							System.out.println(getName()+s2+"使用"+R2+"请求"+R1);
							synchronized(s1){
								System.out.println(getName()+"获取"+R1+"执行");
							}
					}
				}
			}
		}.start();
	}

}

运行结果:

Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-0获取资源2执行
Thread-0线程1使用资源1请求资源2
Thread-1线程2使用资源2请求资源1

造成了死锁的现象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值