Day22 线程

学习目标

1:线程的概念
2:Thread类和Runnable接口
3: 主线程与线程的生命周期
4:线程状态控制方法(sleep休眠状态)
5:线程安全threadsafe

学习内容

1:线程的概念

线程和进程的概念
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
并行:多个CPU同时执行多个任务,比如:多个人同时做不同的事
并发:一个CPU(采用时间片)同时执行多个任务,比如秒杀平台,多个人做同件事
线程的相关API
Thread.currentThread().getName()
1.start():1.启动当前线程2.调用线程中的run方法
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():主动释放当前线程的执行权
7.join():在线程中插入执行另一个线程,该线程被阻塞,直到插入执行的线程完全执行完毕以后,该线程才继续执行下去
8.stop():过时方法。当执行此方法时,强制结束当前线程。
9.sleep(long millitime):线程休眠一段时间
10.isAlive():判断当前线程是否存活

2:Thread类和Runnable接口

thread类
Java中,创建线程的方法有两种:一是通过继承线程类Thread来创建线程;二是建立一个实现Runnable接口的类。

例如:

package Demo01;

public class demo01MainThread {
	public static void main(String[] args) {
	Person p1=new Person("小强");
			p1.run();
			Person p2=new Person("小刚");
			p2.run();

}
}
package Demo01;

public class Person {
	  private String name;
      

	public String getName() {
	return name;
	}
	public void setName(String name) {
	this.name = name;
	}
	public Person(String name) {
	this.name = name;
	}
	public Person() {
		
	}
	
	
	
	  public void run() {
	        for(int i=0;i<20;i++) {
	        	System.out.println(name+"-->"+i);
			}
	        }
	        
	

}


结果为:
在这里插入图片描述
例如2:

package Demo01;

public class Demo01Thread {
	public static void main(String[] args) {
		MyThread mt= new  MyThread();
		mt.start();
	
     for (int i = 1; i <= 20; i++) {
		            System.out.println("主线程"+i);
		        }
		    
}
}
package Demo01;
//创建thread类

	public class MyThread extends Thread {
	//重写run	 
	    
	    @Override
	    public void run() {
	        for (int i = 1; i <= 20; i++) {
	            System.out.println("子线程:"+i);
	        }
	    }
	
}

结果为:
在这里插入图片描述
Runnable接口
从 NEW 到 RUNNABLE 状态

​Java 刚创建出来的 Thread 对象就是 NEW 状态,而创建 Thread 对象主要有两种方法。一种是继承 Thread 对象,重写 run() 方法。示例代码如下:

// 自定义线程对象

class MyThread extends Thread {
public void run() {
// 线程需要执行的代码

}

}

// 创建线程对象

MyThread myThread = new MyThread();

另一种是实现 Runnable 接口,重写 run() 方法,并将该实现类作为创建 Thread 对象的参数。示例代码如下:

// 实现 Runnable 接口

class Runner implements Runnable {
@Override

public void run() {
// 线程需要执行的代码

}

}

// 创建线程对象

Thread thread = new Thread(new Runner());
步骤如下:1.定义类实现Runnable接口

2.覆盖Runnable接口中的run方法(将线程要运行的代码存放在run方法)

3.通过Thread类建立线程对象

4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数

(因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法 ,就必须明确改run方法所属的对象)

5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法

和继承Thread的实现多线程的区别如下:

1.避免了单继承的局限性(在定义线程是建议使用Runnable接口实现)

2.存储位置不同(继承方式:线程代码存放Thread子类的方法中

实现Runnable 线程代码存放在接口的子类的run方法中


例如:

package Demo4;

public class Demo4Runnable {
public static void main(String[] args) {
	Thread t = new Thread(new RunnableImpl2());
	t.start();
	for (int i = 0; i < 20; i++) {
		System.out.println(Thread.currentThread().getName()+"-->"+i);
		
	}
}
}

package Demo4;

public class RunnableImpl {
public void run() {
	for (int i = 0; i < 20; i++) {
		System.out.println(Thread.currentThread().getName()+"-->"+i);
		
	}
}
}

package Demo4;

public class RunnableImpl2 implements Runnable{
	public void run() {
		for (int i = 0; i < 20; i++) {
			System.out.println("helloworld"+i);
		}
			
		}
}

结果为:
在这里插入图片描述
在这里插入图片描述

3: 主线程与线程的生命周期

通用的线程生命周期基本上可以用下图这个“五态模型”来描述。这五态分别是:初始状态、可运行状态、运行状态、休眠状态和终止状态。
在这里插入图片描述
例如:

package Demo02;

import Demo01.MyThread;

public class demo01Thread {
	public static void main(String[] args) {
		MyThread mt= new  MyThread();
		mt.start();
		
	new MyThread().start();
	new MyThread().start();
	new MyThread().start();
	  System.out.println("main:"+Thread.currentThread().getName());

	}
	
}

package Demo02;

public class MyThreadName  extends Thread {
      public MyThreadName() {}
      public MyThreadName(String name) {
    	  super(name);
      }
      @Override
      public void run ()
      {
    	  System.out.println("子:"+Thread.currentThread().getName());

      }
      
}

结果为:
在这里插入图片描述
例如2:

package Demo02;

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

package Demo02;


	public class MyThread extends Thread {
		//重写run	 
		
		    @Override
		    
		    public void run() {
		    	System.out.println("子"+Thread.currentThread().getName());
		    
		    
		        }
		    }
	

结果为:
在这里插入图片描述

4:线程状态控制方法(sleep休眠状态)

sleep方法是Thread类中的一个静态方法,当一个执行中的线程调用了Thread的sleep方法之后,调用线程会暂时让出指定时间的执行权,这期间不参与CPU的调度,但是该线程所拥有的监视器资源,比如锁还是持有且不让出的。指定的睡眠时间到了之后,sleep函数会正常返回,线程就处于就绪状态,然后参与CPU调度,获取到CPU的资源后就可以运行了。
例如:

package Demo03;

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

结果为:

在这里插入图片描述

5:线程安全threadsafe

线程之间存在“竞争条件”,作用于同一个mutable数据上的多个线程,彼此之间存在对该数据的访问竞争并导致interleaving,导致post-condition可能被违反,这是不安全的。
线程安全:ADT或方法在多线程中要执行正确。
要做到:不违反spec,保持RI。与多少处理器,如何调度线程无关,不需要在spec中强制要求client满足某种“线程安全”的义务。

例如:Iterator就不是线程安全的,因为你不能在迭代遍历的时候改变collection。

保证线程安全,有四种策略:

(1)限制数据共享(Confinement)

(2)共享不可变数据(Immutability)

(3)共享线程安全的可变数据(Threadsafe data type)

(4)同步机制(Synchronization)
例如:

package Demo05ThreadSafe;

public class demo01Ticket {
	
	    public static void main(String[] args) {
	        RunnableImpl run=new RunnableImpl();
	        Thread t0=new Thread(run);
	        Thread t1=new Thread(run);
	        Thread t2=new Thread(run);

	        t0.start();
	        t1.start();
	        t2.start();
	    }
	}


package Demo05ThreadSafe;


	/*
	解决线程安全的一种方案:使用同步代码块
	格式:
	    synchronized(锁对象){
	        可能会出现线程安全的代码(是因为访问了共享的数据)
	    }
	    注意:
	        1、通过代码块中的锁对象,可以使用任意的对象
	        2、但是必须保证多个线程使用的锁对象是同一个
	        3、锁对象作用:
	            把同步代码块锁住,只让一个线程执行
	 */
	public class RunnableImpl implements Runnable{
	    private int ticket = 100;
	    Object obj=new Object();
	    @Override
	    public void run() {
	        while (true) {
	            synchronized (obj) {
	                if (ticket > 0) {
	                    try {
	                        Thread.sleep(10);
	                    } catch (InterruptedException e) {
	                        e.printStackTrace();
	                    }
	                    System.out.println(Thread.currentThread().getName() + "--->正在卖第" + ticket + "张票");
	                    ticket--;
	                }
	            }

	        }
	    }
	}



结果为:

在这里插入图片描述
202080605041

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值