day22.java

17 篇文章 0 订阅
10 篇文章 0 订阅

线程、同步

1.1 多线程原理

代码如下:

package Demo1;

public class Demo01MainTherad {
public static void main(String[] args) {
	proson p1 = new proson("湫");
	p1.run();
	
	proson p2 = new proson("鲲");
	p2.run();
}
}

package Demo1;

public class proson {
		private String name;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}
		
		public proson(String name) {
			this.name = name;
		}
		public proson() {
			super();
			// TODO 自动生成的构造函数存根
		}

	public void run() {
		for (int i =0;i<20;i++) {
			System.out.println(name+"");
		}
	}
}
结果:
湫湫湫湫湫湫湫湫湫湫湫湫湫湫湫湫湫湫湫湫
鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲鲲

1.2Thread类

在上一天内容中我们已经可以完成最基本的线程开启,那么在我们完成操作过程中用到了 java.lang.Thread 类, API中该类中定义了有关线程的一些方法,具体如下: 构造方法:
public Thread() :分配一个新的线程对象。 public Thread(String name) :分配一个指定名字的新的线程对象。 public Thread(Runnable target) :分配一个带有指定目标新的线程对象。 public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。 常用方法: public String getName() :获取当前线程名称。 public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。 public void run() :此线程要执行的任务在此处定义代码。 public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。 public static Thread currentThread() :返回对当前正在执行的线程对象的引用。 翻阅API后得知创建线程的方式总共有两种,一种是继承Thread类方式,一种是实现Runnable接口方式,方式一我 们上一天已经完成,接下来讲解方式二实现的方式。

1.3 创建线程方式

二 采用 java.lang.Runnable 也是非常常见的一种,我们只需要重写run方法即可。 步骤如下: 1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。 2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正 的线程对象。 3. 调用线程对象的start()方法来启动线程。 代码如下:

package Demo1;
/*
 * java.long.Thread
 * 
 * 
 * 实现步骤:
 * 1.创建一个Thread类的子类
 * 2.在Thread子类中重写run的方法
 * 3、创建Thread子类对象
 * 4、调用Thread子类方法start启动线程,run
 * 
 * 
 * 
 * */
public class Demo01Thread {
		public static void main(String[] args) {
			//3.创建thread的子类的对象
			MyThread mt =new MyThread();
			
			//4.调用start方法
			mt.start();
			for (int i =0;i<20;i++) {
				System.out.println("主线程:"+i);
				if(i==10) {
					System.out.println(0/0);
				}
			}
		}
}
package Demo1;
/*
 * 创建Thread子类
 * 
 * */
public class MyThread extends Thread {
	//2.重写run
	public void run() {
		
		for (int i =0;i<20;i++) {
			System.out.println("子线程:"+i);
			
		}
	}
}
主线程:0
主线程:1
子线程:0
主线程:2
子线程:1
主线程:3
子线程:2
主线程:4
子线程:3
主线程:5
子线程:4
主线程:6
子线程:5
主线程:7
子线程:6
主线程:8
子线程:7
主线程:9
子线程:8
主线程:10
子线程:9
子线程:10
子线程:11
子线程:12
Exception in thread "main" 子线程:13
子线程:14
子线程:15
子线程:16
子线程:17
java.lang.ArithmeticException: / by zero
子线程:18
子线程:19

1.4 Thread和Runnable的区别

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
总结: 实现Runnable接口比继承Thread类所具有的优势: 1. 适合多个相同的程序代码的线程去共享同一个资源。 2. 可以避免java中的单继承的局限性。 3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。 4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。 扩充:在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用 java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实在就是在操作系统中启动了一个进 程。

Thread

package demo02;
/*
 * java.long.Thread
 * 
 * 
 * 实现步骤:
 * 1.创建一个Thread类的子类
 * 2.在Thread子类中重写run的方法
 * 3.创建Thread子类对象
 * 4.调用Thread类中方法start启动线程,执行run方法
 * 
 * 
 * 
 * */
public class Demo01Thread {
		public static void main(String[] args) {
			//3.创建thread的子类的对象
			MyThread mt =new MyThread();
			
			//4.调用start方法
			mt.start();
			new MyThread().start();//线程 1
			
			new MyThread().start();//线程 3
			new MyThread().start();//线程 2
			System.out.println("main:"+Thread.currentThread().getName());
			}
		}


public class MyThreadName extends Thread {
	public MyThreadName() {}
	
	public MyThreadName(String name) {
		super(name);//把线程的名字传递给父类,让父类Thread给子线程起名字
	}
	public void run() {
		
		//String name=getName();

		//System.out.println("run"+name);
			System.out.println("子:"+Thread.currentThread().getName());
			}
}

结果
main:main
子Thread-1Thread-3Thread-0Thread-2

Runnable

package demo02;

public class Demo02MyThreadSetName {
	public static void main(String[] args) {
		MyThreadName mt =new MyThreadName("小钱");
		mt.start();
		
		new MyThreadName("旺财").start();
		
	}

}
package demo02;
/*
 * 创建Thread子类
 * 
 * */
public class MyThread extends Thread {
	//2.重写run
	public void run() {
		
	//String name=getName();

	//System.out.println("run"+name);
		System.out.println("子"+Thread.currentThread().getName());
		}
	}
结果
子:小钱
子:旺财

2.Timed Waiting(计时等待)

Timed Waiting在API中的描述为:一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态。单独 的去理解这句话,真是玄之又玄,其实我们在之前的操作中已经接触过这个状态了,在哪里呢? 在我们写卖票的案例中,为了减少线程执行太快,现象不明显等问题,我们在run方法中添加了sleep语句,这样就 强制当前正在执行的线程休眠(暂停执行),以“减慢线程”。 其实当我们调用了sleep方法之后,当前执行的线程就进入到“休眠状态”,其实就是所谓的Timed Waiting(计时等 待),那么我们通过一个案例加深对该状态的一个理解。
实现一个计数器,计数到60,在每个数字之间暂停1秒,

package Demo3;

public class Dem03Sleep {
public static void main(String[] args) {
	for(int i=0;i<60;i++) {
		System.out.println(i);
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}
}
}

通过案例可以发现,sleep方法的使用还是很简单的。我们需要记住下面几点: 1. 进入 TIMED_WAITING 状态的一种常见情形是调用的 sleep 方法,单独的线程也可以调用,不一定非要有协 作关系。 2. 为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程 中会睡眠 3. sleep与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。 小提示:sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就 开始立刻执行。

3.Runnable和runnable

package Demo04;

public class Demo04Runnable {
public static void main(String[] args) {
	//3.创建一个Runnble 接口的实现类 对象
	Runnablelmpl run =new Runnablelmpl();
	 //4.创建对象,构造方法中传递Runnable接口实现类对象
	//Thread t=new Thread(run);
	 //5.调用Thread类start方法,启动子线程
	Thread t=new Thread(new Runalelmpl2());
	t.start();
	for(int i=0;i<20;i++) {
		System.out.println(Thread.currentThread().getName()+"-->"+i);
	}
}
}
package Demo04;
//1.创建一个runnable接口的实现类
public class Runnablelmpl implements Runnable {

	@Override
	public void run() {
		// TODO 自动生成的方法存根
		for(int i=0;i<20;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}

}
package Demo04;
//创建一个runnable接口实现类
public class Runalelmpl2 implements Runnable  {
	//实现类中重写runnable中run方法,设置线程任务
	@Override
	public void run() {
		// TODO 自动生成的方法存根
		for(int i=0;i<20;i++) {
			System.out.println("HelloWorld-->"+i);
		}
	}
}


4. 线程安全

如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样 的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 我们通过一个案例,演示线程的安全问题: 电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “葫芦娃大战奥特曼”,本次电影的座位共100个 (本场电影只能卖100张票)。 我们来模拟电影院的售票窗口,实现多个窗口同时卖 “葫芦娃大战奥特曼”这场电影票(多个窗口一起卖这100张票) 需要窗口,采用线程对象来模拟;需要票,Runnable接口子类来模拟 模拟票:

package demo05;

public class Demo01Ticket {
	public static void main(String[] args) {
		
		Runnablempl run =new Runnablempl();
		
		Thread t0= new Thread(run);
		Thread t1= new Thread(run);
		Thread t2= new Thread(run);
		
		t0.start();
		t1.start();
		t2.start();
	}
	}

package demo05;
/*
 * 解决线程安全问题的方案:使用同步代码块
 * 格式:
 * synchronized(锁对象) {
 *              可能会出现的安全代码(是因为访问了共享的数据)
 * } 
 *  注意:
 *  1、通过代码块中的锁对象,
 *  2、但是
 *  3、           
 * 
 */

public class Runnablempl implements Runnable {
	private int ticket =100;
	Object obj= new Object();
	public void run() {
		// TODO 自动生成的方法存根
		while(true) {
			
			//synchronized(obj) {
				if(ticket>0) {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"-->"+ticket+"张票");
				ticket--;
			}
				//}
			
			}
		}
  }


在这里插入图片描述这有错误
改整

package demo05;

public class Demo01Ticket {
	public static void main(String[] args) {
		
		Runnablempl run =new Runnablempl();
		
		Thread t0= new Thread(run);
		Thread t1= new Thread(run);
		Thread t2= new Thread(run);
		
		t0.start();
		t1.start();
		t2.start();
	}
	}
package demo05;
/*
 * 解决线程安全问题的方案:使用同步代码块
 * 格式:
 * synchronized(锁对象) {
 *              可能会出现的安全代码(是因为访问了共享的数据)
 * } 
 *  注意:
 *  1、通过代码块中的锁对象,
 *  2、但是
 *  3、           
 * 
 */

public class Runnablempl implements Runnable {
	private int ticket =100;
	Object obj= new Object();
	public void run() {
		// TODO 自动生成的方法存根
		while(true) {
			
			synchronized(obj) {
				if(ticket>0) {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"-->"+ticket+"张票");
				ticket--;
			}
				}
			
			}
		}
  }

2020080605013

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值