27 多线程(一)——创建进程的三种方法、线程锁(同步synchornized与lock)

线程的流程

 

线程的创建

有三种方法,重点掌握前两种:

  • 继承Thread类
  • 实现Runnable接口(推荐使用:避免单继承的局限性)
  • 实现Callable接口

根据java的思想,要少用继承,多用实现。

第一种:继承Thread类

继承Thread的类必需重写run方法,run方法即为线程体

当程序执行到start()时,不会等这句执行完,继续往下走,main方法与t中的run方法并发执行。

代码:

package _20191203;
/**
 * 创建线程的方法一:继承Thread
 * @author UID
 *
 */
public class ThreadTest extends Thread{ 
	public static void main(String[] args) {
		ThreadTest t = new ThreadTest();
		t.start();//当程序执行到这里时,不会等这句执行完,继续往下走,main方法与t中的run方法并发执行
		for(int i = 0;i < 500;i++) {
			System.out.println("一边听歌");
		}
	}
	@Override
	public void run() { //必需重写run方法
		super.run();
		for(int i = 0;i < 800;i++) {
			System.out.println("一边敲代码");
		}
	}
}

  

看看效果(结果有所截取):

一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边听歌
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码
一边敲代码

  

第二种:实现Runnable接口

类直接实现Runnable接口,在类中写run方法,通过代理类Thread来调用它即可开启线程。

只使用一次的对象推荐使用匿名对象:

new Thread(new xxx()).start();//xxx为实现了Runnable接口的类

  

代码:

package _20191203;
/**
 * 创建线程的方法一:继承Thread
 * @author UID
 *
 */
public class ThreadTest implements Runnable{ 
	public static void main(String[] args) {
		new Thread(new ThreadTest()).start();//对象只使用一次时推荐使用匿名对象
		for(int i = 0;i < 200;i++) {
			System.out.println("一边听歌");
		}
	}
	@Override
	public void run() { //必需重写run方法
		for(int i = 0;i < 200;i++) {
			System.out.println("一边敲代码");
		}
	}
}

  

第三种:实现Callable接口

这种方式,一般中小企业不会用到,它是一种高级方法,一般也要工作3到5年提升时才会学到,在这里只做了解,面试用。

流程:

需要做线程的类实现Callable接口,如:

一般要写上泛型。

public class Test implements Callable<泛型>{}

  

实现Callable的类必需重写call方法,相当于run方法:

他需要有返回值。

public <泛型> call() Throws Exception{}

  

然后在使用线程的方法中(如main方法):

主要有以下步骤

//新建执行服务对象
ExecutorService es = Executors.newFixedThreadPool(线程数量); //提交执行
Future<泛型> result1 = es.submit(r1);//r1为实现了Callable接口的示例,有几个就写几行这行代码 //获取结果
泛型对应的类型 res1 = result1.get();如:Integer res1 = result1.get(); //关闭服务
es.shutdownNow();

  

龟兔晒跑的示例:

package _20191203;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 多线程,龟兔赛跑
 * @author UID
 *
 */
public class Race implements Callable<Integer>{
	private String winner;
	@Override
	public Integer call() throws Exception{
		
		// TODO Auto-generated method stub
		for (int step = 1; step <= 100; step++) {
			System.out.println(Thread.currentThread().getName()+"--->"+step);
			if(winner != null) {
				break;
			}else if(step==100) {
				System.out.println("胜利者:"+Thread.currentThread().getName());
				return step;
			}
		}
		return null;
	}
	
	public static void main(String[] args) {
		Race r1 = new Race();
		Race r2 = new Race();
	
		//创建执行服务
		ExecutorService es = Executors.newFixedThreadPool(2);
		//提交执行
		Future<Integer> result1 = es.submit(r1);
		Future<Integer> result2 = es.submit(r2);
		//获取结果
		try {
			Integer res1 = result1.get();
		} catch (InterruptedException | ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			Integer res2 = result2.get();
		} catch (InterruptedException | ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//关闭服务
		es.shutdownNow();
		
		
	}
}

  

线程Thread类的构造方法与不安全线程

Thread(Runnable target,String name);

通过该构造方法创建线程时可以给线程起一个名字,这个名字可以使用Thread.currentThread().getName()来获取

例子:

抢票模拟,线程不安全型:

package _20191203;
/**
 * 模拟抢票:此代码线程不安群
 * @author UID
 *
 */
public class Thread12306 implements Runnable{
	private int source = 100;
	public void run() {
		while(source>0) {
			source--;
			System.out.println(Thread.currentThread().getName()+" 抢到了票!还剩:"+source);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	
	public static void main(String[] args) {
		Thread t1 = new Thread(new Thread12306(),"线程1");
		Thread t2 = new Thread(new Thread12306(),"线程2");
		Thread t3 = new Thread(new Thread12306(),"线程3");
		t1.start();
		t2.start();
		t3.start();
		
	}
}

  

运行结果,线程不安全的后果:

 

 

posted @ 2019-12-03 09:44  Scorpicat  阅读(247)  评论(0编辑  收藏  举报