多线程基础
了解多线程
不再概述。。。。百度都有
多线程的三种方式
Thread
package com.jiang.thread01;
/**
* @Title: 继承Thread
* @author: JiangPeng
*/
//继承thread类,重写run方法,调用start方法进行启动
public class thread01 extends Thread {
public static void main(String[] args) {
//创建子类对象
thread01 t = new thread01();
t.start(); //调用子类对象的start方法
for(int i=0;i<10000;i++){
System.out.println("我在写代码");
}
}
@Override //线程的入口点
public void run() {
//线程体
for(int i=0;i<10000;i++){
System.out.println("我在听歌");
}
}
}
- 我们要继承Thread,重写Thread类的run方法。
- 这个run()方法就是我们线程的入口点
- run方法内部就是我们的线程体,我们在线程体中输出1万次我在听歌
- 在主方法下,我们首先要创建子类对象,通过子类对象调用start方法启动线程
- 在启动线程后 输出1万次的我的在写代码。
- 此时我们可以在控制台看到,我的写代码和我在听歌是一前一后一前一后,不规则排序,这就是因为我们启动多线程之后,两条输出语句是同时被CPU进行处理,但是先后顺序我们是控制不了,只靠CPU随机选择。
- 当然如果你把 start方法启动线程放在最后,那么你会看到1万次我在写代码之后再1万次我在听歌。
- start是开启线程,会自动调用run方法。run方法只是一个单纯方法。
Runnable(推荐)
package com.jiang.thread01;
/**
* @Title:
* @author: JiangPeng
*/
//实现runnable
public class thread02 implements Runnable {
public static void main(String[] args) {
//创建实现类对象
thread02 t = new thread02();
//创建代理类对象
Thread thread = new Thread(t);
thread.start(); //调用代理类对象的start方法
//-------
//我们上面的thread02实现类对象,和thread代理类对象都只用了一次
//所以我们可以通过匿名的方式进行一次性调用
new Thread(new thread02()).start(); ///都是一样的效果
for(int i=0;i<10000;i++){
System.out.println("我在写代码");
}
}
@Override //线程的入口点
public void run() {
//线程体
for(int i=0;i<10000;i++){
System.out.println("我在听歌");
}
}
}
- 首先实现Runnable接口。重写run方法,run是线程的入口点,方法内就是线程体
- Runnable与Thread不同的是,Runnable需要创建代理类对象
- 即先创建实体类对象 thread02 然后创建thread代理类对象。因为runnable无法直接调用start方法
- 当然我们上面的thread02实现类对象,和thread代理类对象都只用了一次,所以我们可以通过匿名的方式进行一次性的调用
new Thread(new thread02()).start();
效果都是一样的
-
推荐使用实现Runnable,避免单继承局限
-
也方便共享资源
package com.jiang.thread01; /** * @Title: Runnable共享资源,模拟12306抢票 * @author: JiangPeng */ public class Web12306 implements Runnable { private int piao = 100; @Override public void run() { while (true){ if(piao<0){ break; } System.out.println(Thread.currentThread().getName()+">>"+piao--); } } public static void main(String[] args) { Web12306 web = new Web12306(); new Thread(web,"xiaowang").start(); new Thread(web,"xiaochen").start(); new Thread(web,"xiaomeng").start(); } }
- currentThread():当前线程
- 当然在这里会有一系列的问题,涉及后面的并发,目前不做解释。
Callable
- 设计并发编程内容,以后再写
静态代理
package com.jiang.thread01;
/**
* @Title: 静态代理
* @author: JiangPeng
*
* 1.真实角色
* 2.代理角色
*/
public class StaticProxy {
public static void main(String[] args) {
new Wedding(new You()).happyMarry();
//new Thread(线程对象).start();
}
}
interface Marry{
void happyMarry();
}
//真实角色
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("Marry Happy");
}
}
//代理角色
class Wedding implements Marry{
// 真实角色
private Marry target;
public Wedding(Marry target){
this.target=target;
}
@Override
public void happyMarry() {
ready();
this.target.happyMarry();
after();
}
private void ready(){
System.out.println("---Marry ready---");
}
private void after(){
System.out.println("---Marry after---");
}
}
- 接口Marry:里面有happymarry的方法
- 类You:真实角色,实现Marry接口,重写happymarry方法
- 类Wedding:代理角色,实现Marry接口,重写happymarry方法
- 内部有真实角色 target
- 通过构造函数this.target= target
- 主方法
new Wedding(new You()).happyMarry();
=//new Thread(线程对象).start();
Lambda简化
简单,用一次的线程进行简化
package com.jiang.thread01;
/**
* @Title: Lambda简化
* @author: JiangPeng
*/
public class LambdaThread {
public static void main(String[] args) {
new Thread(()->{
//线程体
for(int i=0;i<10000;i++){
System.out.println("我在听歌");
}
}
).start();
}
}
线程状态
五个状态
- 新生状态:new Thread()...一旦创建就进入到新生状态,有自己的工作空间了,与主内存进行交互
- 就绪状态:start()...进入就绪状态,只能表示具备运行的能力,还没有分配到CPU,处于就绪队列
- 运行状态:被CPU调度运行
- sleep:抱着资源,不给别人用。
- wait:等待,可以给别人用
- join:插队
- read write
- 阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态
- 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
- 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
- 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
- 死亡状态:执行完毕,或者stop方法
就像大学生毕业>>准备找工作>>上班>>被裁
线程终止
终止线程:
1.线程正常结束--》次数
2.外部干涉 --》加入标识
不要使用stop/destory方法,不安全。
package com.jiang.thread01;
/**
* @Title:
* @author: JiangPeng
*/
public class TerminateThread implements Runnable {
//加入标识,标记线程体是否可以运行。
private boolean flag = true;
private String name;
public TerminateThread(String name) {
this.name = name;
}
@Override
public void run() {
int i = 0;
//关联标识,true->运行,false->停止。
while(flag){
System.out.println(name+"-->"+i++);
}
}
//对外提供方法,改变标识
public void terminate(){
this.flag=false;
}
public static void main(String[] args) {
TerminateThread terminateThread = new TerminateThread("jack");
new Thread(terminateThread).start();
for (int i=0;i<=99;i++){
if(i==88){
terminateThread.terminate();//线程终止
System.out.println("线程手动终止");
}
System.out.println("main->"+i);
}
}
}
暂停sleep
package com.jiang.thread01;
/**
* @Title:
* @author: JiangPeng
*/
public class BlockedSleep {
public static void main(String[] args) {
Web12306 web = new Web12306();
new Thread(web,"xiaowang").start();
new Thread(web,"xiaochen").start();
new Thread(web,"xiaomeng").start();
}
static class Web12306 implements Runnable {
private int piao = 100;
@Override
public void run() {
while (true) {
if (piao < 0) {
break;
}
try{
Thread.sleep(200);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ">>" + piao--);
}
}
}
}
通过 Thread.sleep(200);
使的进程之间暂停200秒后进行下一步的操作
sleep模拟了网络延时,增大了出现问题的可能性
礼让yield
让当前正在执行的线程暂停,不是阻塞线程,而是将线程从运行状态转入就绪状态,让cpu重新调度
package com.jiang.thread01;
/**
* @Title:
* @author: JiangPeng
*/
public class Yield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+">>start");
Thread.yield();
System.out.println(Thread.currentThread().getName()+">>end");
}
}
其实就是怕防止某个进程一直使用。比如抢票 不能让某个黄牛一直都能抢得到
插队join
合并线程,插队线程
package com.jiang.thread01;
/**
* @Title:
* @author: JiangPeng
*/
public class BlockedJoin {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
for (int i=0;i<100;i++){
System.out.println("lambda..."+i);
}
});
t.start();
for (int i=0;i<100;i++){
if(i==20){
t.join();//插队,main被阻塞了
}
System.out.println("mian..."+i);
}
}
}