进程、线程
启动线程有三种方式
第一:通过Thread的start方法启动
1.一个程序代表一个进程。程序启动后,程序中的每项任务代表一个线程
进程的最小单位是线程
#案例:定义一个类集成Thread类,并重写run方法
public class QrcodeThread extends Thread {
public void run() {
for(int i = 0;i< 2; i++){
System.out.println("qrcodethread");
}
}
public static void main(String[] args) {
//new QrcodeThread().run();
new QrcodeThread().start();
System.out.println("main");
}
}
调用:
方式一:new QrcodeThread().run();
qrcodethread
qrcodethread
main
注:还是顺序执行,先执行run。未使用线程
方式二:new QrcodeThread().start();
qrcodethread
main
qrcodethread
注:还是交替执行,不同线程同时运行
第二:通过接口实现类Runnable启动
#示例:
public class QrcodeThread {
static class MyRun implements Runnalbe{
@Override
public void run(){
System.out.println("hello MyRun");
};
}
}
new Tread(new MyRun()).start();
第三:通过lambda表达式启动线程
new Thread(()->{
System.out.println("hello lambda");
}).start();
第四:通过线程池来启动线程 Executors.newCachedThrad
注:其实也是通过1,2方式启动
synchronized关键字 多个线程访问同一资源时,需要对资源上锁
实际案例:多窗口同时售卖电影票。
/**
* @PACKAGE_NAME: PACKAGE_NAME
* @Description:
* @Author: liangxu
* @Date: 2021/8/14 11:06 上午
* @Version: V1.0
*/
public class Ticket implements Runnable{
private int ricknum = 100;//电影票数量
@Override
public void run() {
while (true){//一直售卖 死循环
if(ricknum > 0){//判断是否有票
//有票,让线程睡眠100毫秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印当前售出的票数字和线程名
final String name = Thread.currentThread().getName();
System.out.println("线程:"+name+"销售电影票:"+ ricknum);
//票数-1
ricknum -- ;
System.out.println("线程:"+name+"销售电影票:"+ ricknum);
}
}
}
public static void main(String[] args) {
//创建电影票对象
Ticket ticket = new Ticket();
//创建Thread对象,执行电影票售卖
new Thread(ticket,"窗口1").start();
new Thread(ticket,"窗口2").start();
new Thread(ticket,"窗口3").start();
}
/**
* 以上出现线程安全问题 售卖结果存在有些票有售卖多次的情况,而且出现了收费票为0和负数的情况
*/
}
public class test {
private int count = 100;//多个线程访问的同一个资源
private Object o = new Object();//线程锁 每个线程需要使用同一把线程锁
public void m(){
//拥有线程锁的 方可执行以下代码
synchronized (o){
count -- ;
System.out.println(Thread.currentThread().getName() + "count = " + count);
}
}
//也可以使用this对象当成锁 这样无需创建锁对象
public void m1(){
synchronized (this){
count -- ;
System.out.println(Thread.currentThread().getName() + "count = " + count);
}
}
//使用this对象等同于次方法
public synchronized void m2(){
count -- ;
System.out.println(Thread.currentThread().getName() + "count = " + count);
}
//静态资源
// private static int count = 100;
// public synchronized static void m1(){ //这里的this代表 synchronized(T.class)
// count -- ;
// System.out.println(Thread.currentThread().getName() + "count = " + count);
// }
}
#案例:抢购100张票
public class TestT implements Runnable {
private int count = 100;
public synchronized void run(){
count -- ;
System.out.println(Thread.currentThread().getName() + "count = " + count);
}
public static void main(String[] args) {
TestT t = new TestT();
for (int i = 0;i<100;i++){
new Thread(t,"Thread"+i).start();
}
}
}
异常锁
程序中如果出现异常,默认锁会被释放掉
死锁
public class TestT implements Runnable {
private int flag;//决定线程走向的标示
private static Object obj1 = new Object(); //加上static 标示该类无论创建多少次,都是唯一的obj1对象
private static Object obj2 = new Object();
public TestT(int flag){
this.flag = flag;
}
public void run(){
if(flag == 1){
//执行线程1代码块
synchronized (obj1){
System.out.println(Thread.currentThread().getName() + "已经获取到资源obj1,请求obj2");
try {
Thread.sleep(1000);//睡眠1s
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2){
System.out.println(Thread.currentThread().getName() + "获取到资源obj2");
}
}
}else{
//执行线程2代码块
synchronized (obj2){
System.out.println(Thread.currentThread().getName() + "已经获取到资源obj2,请求obj1");
try {
Thread.sleep(1000);//睡眠1s
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1){
System.out.println(Thread.currentThread().getName() + "获取到资源obj1");
}
}
}
}
public static void main(String[] args) {
//线程死锁
/**
* 线程1 访问共享资源1 后睡眠 再访问共享资源2(睡眠时,线程2已经获得资源2 并且没有释放)
* 线程2 访问共享资源2 后睡眠 再访问共享资源1 (睡眠时,线程1已经获得资源1 并且没有释放)
* 估导致线程死锁情况
*/
TestT t1 = new TestT(1);
TestT t2 = new TestT(2);
new Thread(t1,"Thread1").start();
new Thread(t2,"Thread2").start();
/**
* 死锁处理
* 1.预防死锁:通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或几个条件,来防止死锁的发生。
* 2.避免死锁:在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免死锁的发生。
* 3.检测死锁:允许系统在运行过程中发生死锁,但可设置检测机构及时检测死锁的发生,来采用适当的措施加以清除。
* 4.解除死锁:当检测出死锁后,便采取适当措施将进程从死锁状态中解脱出来。
*
* 1.2.都会导致性能低下,估我们应采用3.4.处理
*
*
* 四个条件为:
* 1.互斥 (互斥是无法破坏的)
* 2.占有并等待
* 3.不可抢占
* 4.循环等待
*/
}
}