多线程

目录

 

一.线程和进程区别

二.线程的创建和启动

2.1 继承Thread方式

2.2 实现Java.lang.Runnable接口,并实现run() 方法

2.3 总结

三.线程安全问题

3.1 多线程抢票

3.2 解决方案

3.2.1 同步代码块

3.2.2 使用同步方法解决


一.线程和进程区别

二.线程的创建和启动

2.1 继承Thread方式

继承Java.lang.Thread类,并覆盖run() 方法

public class StartThread extends Thread {

	/**
	 * 线程的入口点
	 */
	@Override
	public void run() {
		for(int i=0;i<500;i++){
			System.out.println("一边听歌");
		}
		
	}
	public static void main(String[] args) {
		
		StartThread st = new StartThread();
		st.start();//开启新的线程,不保证立即运行,等待cpu调用
		
		for(int i=0;i<500;i++){
			System.out.println("一边敲代码");
		}
	}

}

运行效果:

 注意:

若上述代码main方法中的 for 循环和 st.start() 位置调换则不会出现上述效果

 

2.2 实现Java.lang.Runnable接口,并实现run() 方法

/**
 * 创建线程方式二:
 * 1、创建:实现Runnable+重写run
 * 2、启动: 创建实现类对象 +Thread对象+ start
 * 
 * 推荐: 避免单继承的局限性,优先使用接口
 * 方便共享资源
 *
 */
public class MyThread implements Runnable {
	/**
	 * 线程入口点
	 * 方法run( )称为线程体
	 */
	@Override
	public void run() {
		for(int i=0;i<500;i++) {
			System.out.println("一边听歌");
		}
	}
	public static void main(String[] args) {	
		Thread t1 = new Thread(new MyThread());
		t1.start();
		for(int i = 0;i < 500;i++){
			System.out.println("一边Coding");
		}
	}
}

2.3 总结

  •  新建的线程不会自动开始运行,必须通过start( )方法启动不能直接调用run()来启动线程,这样run()将作为一个普通方法立   即执行,执行完毕前其他线程无法兵法执行
  •  Java程序启动时,会立刻创建主线程,main就是在这个线程上运行。当不再产生新线程时,程序是单线程的
  • 两种创建线程的比较
    • 继承Thread类方式的多线程
      • 优势:编写简单
      • 劣势:无法继承其它父类
    • 实现Runnable接口方式的多线程
      • 优势:可以继承其它类,多线程可共享同一个Runnable对象
      • 劣势:编程方式稍微复杂,如果需要访问当前线程,需要调用Thread.currentThread()方法
    • 实现Runnable接口方式要通用一些。

三.线程安全问题

3.1 多线程抢票

//多线程并发共享资源安全问题
public class TicketThread implements Runnable {
	int tickets = 100;//火车票数量
	
	@Override
	public void run() {
		//出售火车票
		while(true) {
			//当火车票小于0张,则停止售票
			if(tickets > 0) {
				/*
				 * t1,t2,t3
				 * 假设只剩一张票
				 * t1过来了,他一看有票,他就进来了,但是他突然肚子不舒服,然后他就去上卫生间了
				 * t2也过来了,他一看也有票,他也进来了,但是他的肚子也不舒服,他也去上卫生间了
				 * 
				 * t1上完了卫生间回来了,开始售票
				 * 	tickets = 0;
				 * t2也上完卫生间回来了,他也进行售票
				 *  tickets = -1;
				 * 
				 * 
				 */
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				System.out.println(Thread.currentThread().getName() + ":" +tickets--);
			}
		}
	}

}

运行结果

3.2 解决方案

3.2.1 同步代码块

格式:
  synchronized(锁对象){
      //需要同步的代码
}
/*
 * 问题出现的原因:
 * 		要有多个线程
 * 		要有被多个线程所共享的数据
 * 		多个线程并发的访问共享的数据
 * 
 * 在火车上上厕所
 * 张三来了,一看门是绿的,他就进去了,把门锁上了,门就变红了
 * 李四来了,一看门市红色的,他就只能憋着
 * 张三用完了厕所,把锁打开了,门就变成了绿色
 * 李四一看门变绿了,他就进去了,把门锁上,门就变红了
 * 王五来了,一看们是红色的,他也只能憋着
 * 李四用完测试了,把锁打开了,肚子又不舒服了,扭头回去了,又把门锁上了,
 * 
 * synchronized:同步(锁),可以修饰代码块和方法,被修饰的代码块和方法一旦被某个线程访问,则直接锁住,其他的线程将无法访问
 * 
 * 同步代码块:
 * 			synchronized(锁对象){
 * 
 * 			}
 * 
 * 注意:锁对象需要被所有的线程所共享
 * 
 * 
 * 同步:安全性高,效率低
 * 非同步:效率高,但是安全性低
 * 
 */
public class TicketThread implements Runnable {
	int tickets = 100;//火车票数量
	Object obj = new Object();
	
	@Override
	public void run() {
		//出售火车票
		while(true) {
			synchronized (obj) {

				if(tickets > 0) {
					
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					System.out.println(Thread.currentThread().getName() + ":" +tickets--);
				}
			}
			
		}
	}

}

3.2.2 使用同步方法解决

 格式:

  修饰符 synchronized 返回值 方法名(){

    }
/*
 * 同步方法:使用关键字synchronized修饰的方法,一旦被一个线程访问,则整个方法全部锁住,其他线程则无法访问
 * 
 * synchronized
 * 注意:
 * 		非静态同步方法的锁对象是this
 * 		静态的同步方法的锁对象是当前类的字节码对象
 */
public class TicketThread implements Runnable {
	static int tickets = 100;// 火车票数量
	Object obj = new Object();

	@Override
	public void run() {
		// 出售火车票
		while (true) {
			/*synchronized (obj) {
				method();
			}*/
			
			//method();
			method2();

		}
	}

	private synchronized void method() {
		if (tickets > 0) {
           
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			System.out.println(Thread.currentThread().getName() + ":" + tickets--);
		}
	}
	
	
	private static synchronized void method2() {
	
		if (tickets > 0) {

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

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

	

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值