一、 线程简介
1.线程:
线程是cpu调度和执行的单位。
2.进程 : 是程序的一次执行过程,是系统资源分配的单位。
一个进程可以有多个线程(不同的线程控制不同的功能)
3.程序
注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核
如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点只能执行一段代码,因为切换很快
二、 线程创建
1. 继承类 Thread 类
( 本质上是 该类实现了 Runable 接口)
步骤:
(1) 创建线程类继承 Thread 类, 重写run方法
(2)在主线程main中创建线程类的对象,调用start方法
结果:
注: 线程开启不一定立即执行,由cpu调度执行
注 : 调用run()和start()的区别
public class threadTest extends Thread {
@Override
public void run() {
//在这里重写 该线程的执行逻辑
for(int i=0;i<100;i++){
System.out.println("正在执行线程"+i);
}
}
public static void main(String[] args) {
threadTest t1=new threadTest();
t1.start();
for(int i=0;i<1000;i++){
System.out.println("主线程----"+i);
}
}
}
2.实现接口 Runable 接口
步骤:
(1) 创建线程类 实现了 Runable 接口, 重写run方法
(2)在主线程main中创建线程类的对象,将线程类对象作为参数传入Thread类的构造器
(3)Thread类对象调用start方法
public class threadTest2 implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("正在执行线程"+i);
}
}
public static void main(String[] args) {
threadTest2 t=new threadTest2();
//t.run();
new Thread(t).start();
for(int i=0;i<1000;i++){
System.out.println("主线程----"+i);
}
}
}
注:该方法 避免单继承的局限性,同一个对象可以被多个线程同时使用
线程创建的两种方法的异同
异:
三、线程的状态
注: 线程进入死亡状态就不能再次使用
四、线程方法
1. 线程停止
有对应让线程停止的方法,但是不建议使用
一般使用的是自己创建的stop方法
(1)设置一个标志位flag
(2)在外部控制线程的执行次数
public class threadTest2 implements Runnable{
boolean flag=true;
@Override
public void run() {
// 标志位
while(flag){
System.out.println("正在执行线程"+Thread.currentThread().getName());
}
}
//stop()方法
void stop(){
flag=false;
}
public static void main(String[] args) {
threadTest2 t=new threadTest2();
//t.run();
new Thread(t).start();
for(int i=0;i<500;i++){
System.out.println(Thread.currentThread().getName()+" , "+i);
//程序外面控制线程的运行
if(i==100)
t.stop();
}
}
}
2.线程休眠
sleep(ms) 指定当前线程阻塞的毫秒数,存在异常 InterruptedException
sleep时间到达后线程进入就绪状态
每个对象都有一个锁,但是sleep不会释放锁
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;
public class testSleep implements Runnable {
@Override
public void run() {
for (int i = 20; i > 0; i--) {
try {
Date time = new Date(System.currentTimeMillis());
System.out.println(i +",currentTime: " + new SimpleDateFormat("HH:mm:ss").format(time));
Thread.sleep(1000); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 写一个倒计时
public static void main(String[] args) {
testSleep test = new testSleep();
new Thread(test).start();
for(int i=0;i<1000;i++){
System.out.println(Thread.currentThread().getName());
}
}
}
3.线程礼让 yield()
礼让线程:让当前正在执行的线程暂停,但不阻塞,转为就绪状态
让cpu重新调度,礼让不一定成功
4.线程强制执行 join()
待此线程执行完成之后再执行其他线程。
其他线程处于阻塞状态
5. 线程的优先级
先设置线程的优先级,再启动线程
五、线程同步
1. 多个线程操作同一个资源,需要用到线程同步
2. 同步代码块
本质上是排队+锁
注: 锁可以自己指定,但是必须唯一(对线程来说)
package ThreadTest;
// 三个窗口卖一百张票
public class testTickets extends Thread {
static int Tickets = 100;
static Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (Tickets > 0) {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票");
} catch (InterruptedException e) {
e.printStackTrace();
}
} else break;
}
}
}
public static void main(String[] args) {
testTickets t1 = new testTickets();
testTickets t2 = new testTickets();
testTickets t3 = new testTickets();
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
public class testTickets implements Runnable{
//
int Tickets=100;
// 为什么这里不需要static ?
// 因为这里的线程是实现了Runnable接口,只会创建一个testTickets对象,所以所有的线程共用一份Tickets
@Override
public void run() {
while(true){
synchronized (this) {
if (Tickets > 0) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票" + this);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else break;
}
}
//
}
public static void main(String[] args) {
testTickets test=new testTickets();
Thread t1=new Thread(test,"t1");
Thread t2=new Thread(test,"t2");
Thread t3=new Thread(test,"t3");
t1.start();
t2.start();
t3.start();
}
}
3.同步方法
注:同步方法的锁不能自己指定
1. 静态 :当前类的字节码文件
2. 非静态: this 对象
public class testTickets implements Runnable {
//
int Tickets = 100;
// 为什么这里不需要static ?
// 因为这里的线程是实现了Runnable接口,只会创建一个testTickets对象,所以所有的线程共用一份Tickets
@Override
public void run() {
while (true) {
if (method()) break;
}
//
}
//同步方法的锁不能自己指定
// 1. 静态 :当前类的字节码文件
// 2. 非静态: this 对象
private synchronized boolean method() {
if (Tickets > 0) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票" + this);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else return true;
return false;
}
public static void main(String[] args) {
testTickets test = new testTickets();
Thread t1 = new Thread(test, "t1");
Thread t2 = new Thread(test, "t2");
Thread t3 = new Thread(test, "t3");
t1.start();
t2.start();
t3.start();
}
}
// 三个窗口卖一百张票
public class testTickets extends Thread {
static int Tickets = 100;
static Object obj = new Object();
@Override
public void run() {
while (true) {
if (method()) break;
}
}
private static synchronized boolean method() {
if (Tickets > 0) {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + ":卖出第" + Tickets-- + "票" );
} catch (InterruptedException e) {
e.printStackTrace();
}
} else return true;
return false;
}
public static void main(String[] args) {
testTickets t1 = new testTickets();
testTickets t2 = new testTickets();
testTickets t3 = new testTickets();
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
六、锁
lock
问题: 可否自己设定加锁解锁
LOCK 提供了获得锁和释放锁的方法
1.lock是接口,不能直接实例化,实现类是 ReentrantLock
七、线程池
1.线程池的核心思想:创建容器存储线程
创建线程池,提交任务(提交任务的时候线程池会自动去创建线程)
(1)
public static ExecutorService newCachedThreadPool()
创建的最大线程数是int型数据的最大值,
// 线程池
public class threadPool implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+","+i);
}
}
public static void main(String[] args) {
threadPool t1=new threadPool();
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
}
}
(2)
public static ExecutorService newFixedThreadPool(int nThreads)
// 线程池
public class threadPool implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+","+i);
}
}
public static void main(String[] args) {
threadPool t1=new threadPool();
/* ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
cachedThreadPool.submit(t1);
*/
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
fixedThreadPool.submit(t1);
fixedThreadPool.submit(t1);
fixedThreadPool.submit(t1);
fixedThreadPool.submit(t1);
fixedThreadPool.submit(t1);
fixedThreadPool.submit(t1);
}
}