1.线程中常用的方法
1.static Thread currentThread()得到当前正在运行的线程对象
2.void start() 启动线程
3.String getName()返回该线程的名称。
(1)当没有设置线程名称的时候,系统会赋予线程一个默认的名称“Thread-0,Thread-1......”
(2) 主线程【主方法的执行线程】的名称默认是“main”
4.void setName(String name)设置线程名称
例子:
public class FreadMthods {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread n = new MyThread();
Thread thread1 = new Thread(n);
Thread thread2 = new Thread(n);
//主线程
String mainname = Thread.currentThread().getName();
System.out.println(mainname + "主线程名字"); //主线程的名字默认为main
//改变线程的名字:
//1. 通过献策很难过对象进行设置
thread1.setName("线程1");
thread2.setName("线程2");
//2. 在创建线程对象的时候第二个参数为线程的名字
Thread thread3 = new Thread(n,"线程3");
Thread thread4 = new Thread(n,"线程4");
thread1.start();
thread2.start();
thread4.start();
thread3.start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
// 常用方法
// currentThread()得到当前正在运行的线程对象
//通过getName()返回该线程的名称
//当没有设置线程名称的时候,系统会赋予线程一个默认的名字 Thread-n
//主线程默认名字是main
Thread thisobj = Thread.currentThread();
String thname = thisobj.getName();
int i = 0;
while(true){
i++;
System.out.println(thname + " i + " + i); //默认名字Thread-1 / Thread-2
if (i>50) {
break;
}
}
}
}
5.线程的优先级
就是线程的执行先后概率,默认优先级都是5
void setPriority(int newPriority) 更改线程的优先级。
- 线程的优先级有10级,分别是整数1~10来表示。数字越高优先级越高。
- 为了方便操作,java将10个级别有规定成3个级别,分别为在于低级:1 中级:5 高级: 10
static int MAX_PRIORITY 线程可以具有的最高优先级。10
static int MIN_PRIORITY线程可以具有的最低优先级。1
static int NORM_PRIORITY分配给线程的默认优先级。5
package com20211120;
public class ThreadPriorityTest {
//设置优先级
public static void main(String[] args) {
MyThreadTest1 fn = new MyThreadTest1();
Thread th1 = new Thread(fn,"线程1");
Thread th2 = new Thread(fn, "线程2");
Thread th3 = new Thread(fn,"线程3");
//1.通过1-10整数设置优先级
th1.setPriority(10);
th2.setPriority(5);
th3.setPriority(1);
//2.通过Thread提供的静态常量来设置优先级
th1.setPriority(Thread.MIN_PRIORITY); //优先级最低 为1
th2.setPriority(Thread.NORM_PRIORITY);//优先级中等 为5
th3.setPriority(Thread.MAX_PRIORITY); //优先级最高 为10
th1.start();
th2.start();
th3.start();
System.out.println(th1.getName()+"优先级数" + th1.getPriority());
System.out.println(th2.getName() +"优先级数" + th2.getPriority());
System.out.println(th3.getName() +"优先级数" + th3.getPriority());
}
}
class MyThreadTest1 implements Runnable{
@Override
public void run() {
//默认执行代码
int i = 1;
while(true){
if (i > 50) {
break;
}
String name = Thread.currentThread().getName();
System.out.println(name + " i = " + i++);
}
}
}
int getPriority() 返回线程的优先级。
//2.通过Thread提供的静态常量来设置优先级
th1.setPriority(Thread.MIN_PRIORITY); //优先级最低 为1
th2.setPriority(Thread.NORM_PRIORITY);//优先级中等 为5
th3.setPriority(Thread.MAX_PRIORITY); //优先级最高 为10
th1.start();
th2.start();
th3.start();
System.out.println(th1.getName()+"优先级数" + th1.getPriority());
System.out.println(th2.getName() +"优先级数" + th2.getPriority());
System.out.println(th3.getName() +"优先级数" + th3.getPriority());
设置线程的优先级的时候,数字越大优先级越高,数字越小优先级越低。优先级越高并代表就一定会优先执行,只是被优先执行的几率增大,因此不要试图通过控制线程的优先级,来保证某一个线程,总是第一个执行。
6 守护线程的相关操作方法
(1)用户线程:通常情况之下我们所创建的线程都是普通线程,非守护线程,也叫用户线程。
(2)守护线程:也叫精灵线程,当所有用户线程都执行完毕以后,自动结束运行的线程就是守护线程.[共死]
1.boolean isDaemon() 测试该线程是否为守护线程。
2.void setDaemon(boolean on) 将该线程标记为守护线程用户线程。
特征:当所有用户线程都执行完毕以后,无论守护线程能否可以继续运行,都要立刻停止运行。
例子:
package com20211120;
public class ThreadDeamonTest {
public static void main(String[] args) {
// 线程守护
MyThreadTest myth = new MyThreadTest();
Thread th1 = new Thread(myth);
Thread th2 = new Thread(myth);
Thread th3 = new Thread(){
@SuppressWarnings("static-access")
public void run(){
while(true){
try {
this.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("我是守护线程");
}
}
};
th3.setDaemon(true);
th1.start();
th2.start();
th3.start();
}
}
class MyThreadTest implements Runnable{
@Override
public void run() {
//默认执行代码
int i = 1;
while(true){
if (i > 50) {
break;
}
String name = Thread.currentThread().getName();
System.out.println(name + " i = " + i++);
}
}
}
7static void sleep(long millis) 设置线程休眠【暂停】指定的时间【毫秒】
- void interrupt() 中断线程休眠【暂停】。会进入异常【InterruptedException】。
- void join(long millis)【强制线程执行】等待该线程终止的时间最长为 millis 毫秒。
public class ThreadSleepTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThreadTest3 my3 = new MyThreadTest3();
Thread fn = new Thread(my3,"小明");
System.out.println("开始上课");
fn.start();
try {
Thread.sleep(4000);
fn.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("没叫醒");
}
}
}
class MyThreadTest3 implements Runnable {
@Override
public void run() {
// 上课后
Thread atthis = Thread.currentThread();
String name = atthis.getName();
System.out.println(name + "上课2s开始睡觉");
try {
Thread.sleep(2000);
System.out.println(name + "睡着了");
atthis.join();
} catch (InterruptedException e) {
System.out.println(name + "被叫醒来了");
}
System.out.println(name + "继续上课");
}
}
2.线程的生命周期
1) 线程的声明周期就是线程的从一开始创建,到run方法执行完毕以后的状态变化。【状态之间的切换】。
2)线程的声明周期几种状态【1、新建状态2、就绪状态、3.运行状态、4、阻塞状态、5死亡状态】
线程的声明周期描述
1.新建状态:通过new的方式创建出来的线程对象,此时线程正处于创建状态【新建状态】
* 新建状态的线程不能运行。
* 先将状态的线程调用start方法进入就绪状态。
2.就绪状态:线程具备运行能力,只差操作系统【CUP】分配给他运行时间片
* 得到操作系统【CUP】分配给他运行的时间片,此时开始运行run方法,进入运行状态。
3.运行状态:线程运行run方法
* 回到就绪状态:
1)操作系统【cpu】分配给他运行时间片使用完毕,回到就绪状态
* 进入阻塞状态:
- 运行抓状态的线程执行了sleep方法,进入阻塞状态。
- 运行状态的线程执行了wait方法,进入阻塞状态。
- 运行状态的线程执行输入/输出,进入阻塞状态。
.....等等。
* 进入死亡状态
1)运行状态的线程run方法执行完毕,进入死亡状态。
2)运行状态的线程对象调用了stop()/destory(),进入死亡状态。
4. 阻塞状态:线程暂停运行
*回到运行状态
阻塞状态的线程,结束了造成阻塞的原因,此时线程进入就绪状态,得到操作系统「CPU」分配给他们的运行时间片就可以进入运行状态。
运行状态进入阻塞状态的原因:
1)运行状态的线程执行了sleep方法,进入阻塞状态,休眠时间结束/interrup,进入就绪状态。
2)运行状态的线程执行了wait方法,进入阻塞状态,调用notify/notifyAll,进入就绪状态
3)运行状态的线程执行输入/输出动作,进入阻塞状态,输入/输出结束,进入就绪状态。
5.死亡状态:线程运行结束,释放运行资源。
死亡状态的线程是不能运行的,除非线程对象再次调用start()方法重新启动运行。
图例:
3.线程安全/线程同步
1)为什么我们要学习线程同步/线程安全
线程同步也叫线程安全。当多条线程,同时访问同一个资源的时候,每一次只能由多条线程中的一条访问公共资源,当这一条线程访问公共资源的时候,其他的线程处于等待状态,不能呢个访问公共资源,剩下的线程继续等待,等待当前线程访问结束,实现这个过程叫做线程同步。[排队访问资源]
2)实现方式
(1)Synchronized关键字 [同步代码快/同步方法]
**同步代码块
格式:synchronized(同步对象){
}
package com20211120;
public class SynchronizedTest {
public static void main(String[] args) {
ThreadTest srctarget = new ThreadTest();
Thread thread = new Thread(srctarget,"窗口1");
Thread thread2 = new Thread(srctarget,"窗口2");
Thread thread3 = new Thread(srctarget,"窗口3");
thread.setPriority(1);
thread3.setPriority(Thread.MAX_PRIORITY);
thread.start();
thread2.start();
thread3.start();
}
}
class ThreadTest implements Runnable{
private int count = 0;//统计执行的次数
private int piao = 500;
@Override
public void run() {
Thread thread = Thread.currentThread();
String name = thread.getName();
while (true) {
synchronized (this) {
if (piao <= 0) {
return;
}
System.out.println(name + "卖出一张票,剩余" + (--piao) +"张");
count++;
}
System.out.println("买了" + count+"次票");
}
}
}
注意:如果不写同步对象可能会锁住整个类。
(2)同步方法
原因:同步代码块虽然可以实现效果,但是他在使用的时候,需要设置同步对象,由于我们很多时候不知道同步对象是谁,容易写错,造成思锁。因为这个缺点,我们很少使用同步代码块来实现同步线程。
同步方法个定义格式:
访问限制修饰符 synchronized 方法返回值类型 方法名称(){}
package com20211120;
public class SynchronizedMethodTest {
public static void main(String[] args) {
ThreadTest2 srctarget = new ThreadTest2();
Thread thread = new Thread(srctarget,"窗口1");
Thread thread2 = new Thread(srctarget,"窗口2");
Thread thread3 = new Thread(srctarget,"窗口3");
thread.setPriority(1);
thread3.setPriority(Thread.MAX_PRIORITY);
thread.start();
thread2.start();
thread3.start();
}
}
class ThreadTest2 implements Runnable{
private int count = 0;//统计执行的次数
private int piao = 500;
public synchronized boolean fns(String name){
if (piao <=0 ) {
return false;
}
System.out.println(name + "卖出一张票,剩余" + (--piao) +"张");
count++;
System.out.println("买了" + count+"次票");
return true;
}
@Override
public void run() {
Thread thread = Thread.currentThread();
String name = thread.getName();
boolean flag =true;
while (flag) {
flag = fns(name);
}
}
}
(3)通过Lock接口
public interface Lock
常用方法
void lock()获得锁
void unlock()释放锁
由于上面的锁方法是Lock接口,我们要使用就得先创建出Lock接口对象,由于Lock是个接口不能new,我们就得使用它的子类创建对象。
Lock接口的子类ReentrantLock类
例子:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
public static void main(String[] args) {
ThreadTest4 srctarget = new ThreadTest4();
Thread thread = new Thread(srctarget,"窗口1");
Thread thread2 = new Thread(srctarget,"窗口2");
Thread thread3 = new Thread(srctarget,"窗口3");
thread.setPriority(1);
thread3.setPriority(Thread.MAX_PRIORITY);
thread.start();
thread2.start();
thread3.start();
}
}
class ThreadTest4 implements Runnable{
private int count = 0;
private int piao = 100;
@Override
public void run() {
Thread thread = Thread.currentThread();
String name = thread.getName();
Lock fLock = new ReentrantLock();
while (true) {
fLock.lock();
if (piao <= 0) {
return;
}
System.out.println(name + "卖出一张票,剩余" + (--piao) +"张");
count++;
fLock.unlock();
System.out.println("买了" + count + "次票");
}
}
}
Synchronized关键字与lock的区别
synchronized | Lock |
关键字 | 接口 |
自动锁定资源,不灵活 | 手动锁定资源灵活 |
异常时会自动释放锁 | 异常时不会自动释放锁 所以需要finally实现释放锁 |
不能中断锁,必须等待线程执行完成释放锁 | 可以中断锁 |
无奈源于不够强大