♥线程是进程的一部分,是进程的最小执行单位
1>程序:静态的代码
2>进程:程序动态的执行过程
3>线程:进程内最小的执行单位,是动态的执行过程
进程有自己独立的内存
线程共享进程的资源,在进程内,每个线程可以完成独立的功能
多线程效率高–tomcat服务器
1、创建线程两种方式
extends Thread:是线程
implements Runnable:不是线程,可实现线程
代码须写入线程体run()方法中
启动线程:start()方法
public class MyThread extends Thread{
//主线程
public static void main(String[] args) {
T t1 = new T();
T2 t2 = new T2();
t1.start();
t2.start();
}
}
class T extends Thread {
//线程完成功能代码需要写到线程体方法中run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("hello");
}
}
}
class T2 extends Thread {
//线程完成功能代码需要写到线程体方法中run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("Thread");
}
}
}
//执行结果证明线程没有执行先后顺序,多线程抢占资源
class Runnable1 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i <= 10; i++) {
System.out.println(i);
}
}
}
public class Demo {
public static void main(String[] args) {
Runnable1 r = new Runnable1();
Thread t = new Thread(r);
t.start();
Thread t2 = new Thread(
()->{
for (int i = 0; i <= 10; i++) {
System.out.println("hello");
}
}
);
t2.start();
}
}
练习1:用两种方法创建线程,一个打印奇数一个打印偶数(10以内的)
class Thread2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (i%2 == 0) {
System.out.println(i);
}
}
}
}
class Runnable3 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
if (i%2 != 0) {
System.out.println(i);
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
Thread2 t2 = new Thread2();
t2.start();
Runnable3 r3 = new Runnable3();
Thread t3 = new Thread(r3);
t3.start();
}
}
2、常用方法
//获取正在运行thread
Thread t = Thread.currentThread();
System.out.println(t);//Thread[Thread-0,5,main]线程优先级5,在main方法中
//获取当前线程名
System.out.println(t.getName());
//获取当前线程ID
System.out.println(t.getId());
//查看线程可否使用
System.out.println(t.isAlive());//可用否
//Sleep方法:线程休眠方法
Thread.sleep(1000);
//join方法:等待线程执行完毕
3、守护线程
setDeamon(true);
创建出来的线程:用户线程(前台线程)和守护线程(后台线程),默认用户线程
设置守护线程调用方法setDeamon(true)
用法和创建方式没有区别
区别:用户线程执行完毕,守护线程无条件停止执行
public class Demo6 {
public static void main(String[] args) {
Thread roseThread = new Thread() {
public void run() {
for (int i = 0; i <= 3; i++) {
System.out.println("一起跳");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("扑通。。。");
}
};
Thread jeckThread = new Thread(
()->{
while (true) {
System.out.println("你先跳,我再跳");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
roseThread.start();
jeckThread.setDaemon(true);//在启动线程之前设置线程为守护线程
jeckThread.start();
}
}
4、线程的生命周期
新建状态:new Thread()
就绪状态:start()
阻塞状态:sleep(),wait(),io
运行状态:run()
消亡:执行完run()方法的语句
5、线程的优先级
不同优先级:高优先级先执行,低优先级后执行
同一优先级:先到先服务
public class Demo7 {
public static void main(String[] args) {
Thread t1 = new Thread(
()->{
for (int i = 0; i <= 10 ; i++) {
System.out.println("t1");
}
}) ;
Thread t2 = new Thread(
()->{
for (int i = 0; i <= 10 ; i++) {
System.out.println("t2");
}
}) ;
Thread t3 = new Thread(
()->{
for (int i = 0; i <= 10 ; i++) {
System.out.println("t3");
}
}) ;
t3.setPriority(Thread.MAX_PRIORITY);
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.NORM_PRIORITY);
t1.start();
t2.start();
t3.start();
}
}
6、线程的调度
7、线程的同步
多个线程来操作一个共享变量时,可能会导致共享变量的不完整(不安全)
为了保证共享变量的安全,使用同步机制保证共享变量的安全性
同步机制:当一个线程去改变共享变量值的时候,其它线程不能使用共享变量,当线程计算完成时,返回变量值之后,其它线程才可以使用共享变量
使用synchronized关键字实现线程同步
同步块synchronized
synchronized(锁对象){
共享变量相关的业务代码(运算)
}
在方法上synchronized,用词关键字修饰的方法叫同步方法
public class Demo8 {
static int ticket = 10;
public static void main(String[] args) {
TicketThread tk = new TicketThread();
TicketThread tk1 = new TicketThread();
tk.start();
tk1.start();
}
}
class TicketThread extends Thread{
static int ticket;
public void run() {
while(true) {
synchronized (Demo8.class) {
if (Demo8.ticket <= 0) {
System.out.println("票卖完了");
break;
}
else {
Demo8.ticket--;
System.out.println(Thread.currentThread().getName()+" 卖了1张票,还剩 "+Demo8.ticket+"张");
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Demo9 {
public static void main(String[] args) {
Shopping s = new Shopping();
Thread t1 = new Thread(()-> {
s.test();
});
Thread t2 = new Thread(()-> {
s.test();
});
t1.start();
t2.start();
}
}
class Shopping{
public void test() {
System.out.println(Thread.currentThread().getName()+"选衣服");;
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (this) {
System.out.println(Thread.currentThread().getName()+"试衣服");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
8、同比线程之间的通信
wait();
notify();
notifyAll();
使用两个线程交替打印10个数
class NumThread implements Runnable{
int i = 1;
@Override
public void run() {
synchronized (this) {
while (i<=10) {
notify();//唤醒
System.out.println(Thread.currentThread().getName()+":"+i);
i++;
try {
if(i>10) {break;}//if(i<11) wait();
else {
}wait();//使当前线程处于等在状态
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
NumThread num = new NumThread();
new Thread(num).start();
new Thread(num).start();
}
}
======================================================
sleep()和wait()区别
1、sleep线程类的方法,wait是Object类的方法
2、sleep方法不是释放锁 ,wait是释放锁
3、sleep方法自动醒,wait必须通过使用notify,notifyAll唤醒
======================================================
1、线程的死锁
2、线程池
1>为什么使用线程池
频繁的创建线程,需要消耗时间和内存
2>使用线程池的好处
管理线程
使线程重用
3>创建线程池
newCacheThreadPool() //可创建多个线程
newFixedThreadPool(3) //创建3个线程♥常用♥♥
newScheduledThreadPool(5)
//excute(Runnable的子类,1,5,TimeUnit,SECONDS)
//多个参数可延迟启动,间隔5seconds
newSingleThreadPool() //创建单个线程池
4>关闭线程池
shutdown() //不关闭正在执行的线程
shutdownNow() //不管是否执行完毕都关闭