线程的简单学习

1.线程

1.抢占式运行

CPU在执行的时候,按照时间片来执行的,单位的时间片是抢占是执行,比如 idea qq 抢占CPU的,比如qq的线程抢到cpu,idea线程等待

2.资源共享性

一个线程可以共享当前CPU, 网卡等

Java程序:

一个Java程序就是一个进程 Demo1 就是一个应用程序 就是一个进程

一个Java程序Demo1里面至少 几个线程?

两个:

main主函数线程

JVM垃圾回收器线程

2.线程和进程的区别【面试题】

进程是一个应用程序,是独立的
线程是进程中最小的基本单位
线程有独立性和互斥性
线程有抢占式资源共享特性

3.并发和并行

并发:同时发生,轮流交替执行

并行:真正意义上的同时执行

4.创建线程的两种方式【重点】

1.一个是将一个类声明为Thread的子类,这个子类应该重写run方法,然后可以分配并启动子类的实例

package com.qfedu.a_thread;
class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程1吃水煮肉片" + i);
        }
    }
}
class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程二吃毛血旺" + i);
        }
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        myThread1.start();//启动线程 start方法,在主线程中开启子线程
​
        MyThread1 myThread2 = new MyThread1();
        myThread2.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主函数线程吃大盘鸡" + i);
        }
​
    }
}
​

2.创建一个类实现Runnable接口,然后实现run方法,可以分配类的实例,在创建Thread时作为参数传递,并启动

package com.qfedu.a_thread;
​
class MyThread3 implements Runnable{
​
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程3 " + i);
        }
    }
​
}
class MyThread4 implements Runnable{
​
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程4 " + i);
        }
    }
}
public class Demo2 {
    public static void main(String[] args) {
        MyThread3 myThread3 = new MyThread3();
        //Thread(Runnable target) 参数是Ruannable这个接口对象
        //分配一个新的Thread对象
        Thread thread = new Thread(myThread3);
        thread.start();
​
        MyThread4 myThread4 = new MyThread4();
        Thread thread1 = new Thread(myThread4);
        thread1.start();
​
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程" + i);
        }
    }
}
​

5.线程下面的几个方法

构造方法

Thread()分配一个新的 Thread对象。 无参构造方法
Thread(Runnable target)分配一个新的 Thread对象。 有参构造
Thread(Runnable target, String name)分配一个新的 Thread对象。并起名字

线程方法:

static ThreadcurrentThread()返回对当前正在执行的线程对象的引用
StringgetName()返回此线程的名称。
voidsetName(String name)将此线程的名称更改为等于参数 name
intgetPriority()返回此线程的优先级。
voidsetPriority(int newPriority)更改此线程的优先级。
设置优先并不一定优先,只是增加了执行的概率。最小值是1,最大值是10,默认的是5
static voidsleep(long millis)使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
package com.qfedu.threadfun;
class MyThread1 implements Runnable{
​
    @Override
    public void run() {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
        System.out.println(thread.getPriority());
        thread.setName("线程1");
        thread.setPriority(1);
        System.out.println(thread.getName());
        System.out.println(thread.getPriority());
//        for (int i = 0; i < 500; i++) {
//            System.out.println(thread.getName() + " " + i);
//        }
    }
}
class MyThread2 implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
        System.out.println(thread.getPriority());
        thread.setName("线程2");
        thread.setPriority(10);
        System.out.println(thread.getName());
        System.out.println(thread.getPriority());
//        for (int i = 0; i < 500; i++) {
//            System.out.println(thread.getName() + " " + i);
//        }
    }
}
public class Demo1 {
    public static void main(String[] args) {
        new Thread(new MyThread1()).start();
        new Thread(new MyThread2()).start();
        Thread thread = new Thread();
        System.out.println(thread.getName());
        System.out.println(thread.getPriority());
    }
}
​

6.线程的的锁和同步【重要】

为什么要进行线程的同步?

Java是允许多线程(多个线程),当多个线程操作同一个资源(咋操作)的时候,会导致得到或者打印的数据不准确。从而发生冲突。咋解决?加同步锁。

美团
淘票票
这个两个线程,都去麦同一场次的票
结果美团卖出去一张1排1列的票
结果淘票票也卖出去了1排1列的票  你感觉合适吗?
就是上面的这种结果!!!不合适的,分享同一个资源的时候,要保证分享资源的数据,合法性!!!
​
​
​
分析结果:
    
package com.qfedu.c_sync;
​
//最理想的状态!!!
//先线程1进入到ticket=50,循环 循环结束以后 此时
//tiket=49了
//循环第二次的时候 线程2抢到资源了 此时ticket=49
//循环 打印49 tiket-- ticket=48了
//循环第三次的时候 线程2 抢到资源了, 此时ticket=48
//打印卖第48张票。ticket--  tiket=47
//线程1又抢到循环
//现在的情况是:有可能两个线程同时进入到while循环
//
class MySync implements Runnable {
    int ticket = 50;
    @Override
    public void run() {
        //
        while (true) {//死循环
            //两个线程都进入到了循环了
            //此时两个线程所持有的ticket 都是50
            //但是两个线程都要往下执行
            //有可能线程1 先执行了sout(50)  线程2在等待哦!!!
            //线程1执行了--操作并出了循环 线程1ticket = 49
            //线程1又抢到循环了 sout(49) tiket--
            //再进入倒这个循环,有可能线程2抢到这个执行权
            //线程2要往下执行输出语句  ticket=50 打印50
            if (ticket > 0) {
                //线程具有抢占式的运行
                //咱们有没有可能,线程3进入到if语句
                //此时线程1也进入到if语句了
                //线程3去打印 卖出了50张票
                //在线程1里面  ticket=50
                //线程3又抢到ticket-- 又进入到循环了  ticket = 49
                //线程3又抢到了ticket-- 又进入倒循环 ticket=48
                //线程1又抢到资源要执行,执行输出语句  tiekct=50
                System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票");
                ticket--;
            } else {
                System.out.println("买完了");
                break;//终止循环!!!
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MySync mySync = new MySync();
        //这三个线程
        Thread thread1 = new Thread(mySync, "线程1");
        thread1.start();
        Thread thread2 = new Thread(mySync, "线程2");
        thread2.start();
        Thread thread3 = new Thread(mySync, "线程3");
        thread3.start();
​
​
    }
}
​

解决方案:

1.同步方法:使用一个关键字synchronized修饰方法。因为Java对象都有一个内置的锁对象。当使用这个关键字的时候,修饰方法的时候,这个方法就会被锁保护起来被锁锁住

当一个线程进来以后,会立马锁住当前的方法。意味着只有一个线程进来,其他线程都在外面等着。

public synchronized  void run () {
​
}
package com.qfedu.c_sync;
​
//最理想的状态!!!
//先线程1进入到ticket=50,循环 循环结束以后 此时
//tiket=49了
//循环第二次的时候 线程2抢到资源了 此时ticket=49
//循环 打印49 tiket-- ticket=48了
//循环第三次的时候 线程2 抢到资源了, 此时ticket=48
//打印卖第48张票。ticket--  tiket=47
//线程1又抢到循环
//现在的情况是:有可能两个线程同时进入到while循环
//
class MySync1 implements Runnable {
    int ticket = 50;
    //对这个run方法加了锁 就意味着只有一个线程进入到run方法中
    //其他线程都在run方法外面等待
    @Override
    public synchronized void run() {
        //
        while (true) {//死循环
            //两个线程都进入到了循环了
            //此时两个线程所持有的ticket 都是50
            //但是两个线程都要往下执行
            //有可能线程1 先执行了sout(50)  线程2在等待哦!!!
            //线程1执行了--操作并出了循环 线程1ticket = 49
            //线程1又抢到循环了 sout(49) tiket--
            //再进入倒这个循环,有可能线程2抢到这个执行权
            //线程2要往下执行输出语句  ticket=50 打印50
            if (ticket > 0) {
                //线程具有抢占式的运行
                //咱们有没有可能,线程3进入到if语句
                //此时线程1也进入到if语句了
                //线程3去打印 卖出了50张票
                //在线程1里面  ticket=50
                //线程3又抢到ticket-- 又进入到循环了  ticket = 49
                //线程3又抢到了ticket-- 又进入倒循环 ticket=48
                //线程1又抢到资源要执行,执行输出语句  tiekct=50
                System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票");
                ticket--;
            } else {
                System.out.println("买完了");
                break;//终止循环!!!
            }
        }
    }
}
public class Demo2 {
    public static void main(String[] args) {
        MySync1 mySync = new MySync1();
        //这三个线程
        Thread thread1 = new Thread(mySync, "线程1");
        thread1.start();
        Thread thread2 = new Thread(mySync, "线程2");
        thread2.start();
        Thread thread3 = new Thread(mySync, "线程3");
        thread3.start();
​
        //为啥都是线程1卖出去的票?
        //很巧  线程1抢到执行权了,进入到run方法中
        //线程2和线程3在外面等着。
        //一个循环进来以后,把循环全部执行完!!!
        //会出现一家独大的情况!!!也是不符合咱们生活场景的!!!
        //咋解决?咱们 不能方法中加锁,在其他地方加锁
​
​
    }
}
​

换另外一种解决方法:

同步代码块:就是拥有了synchronized 关键字修饰一个语句块。被修饰的语句块会被加锁。从而实现同步。

语法格式:

synchronized  (this) {
	被加锁的代码块
}
package com.qfedu.c_sync;

//最理想的状态!!!
//先线程1进入到ticket=50,循环 循环结束以后 此时
//tiket=49了
//循环第二次的时候 线程2抢到资源了 此时ticket=49
//循环 打印49 tiket-- ticket=48了
//循环第三次的时候 线程2 抢到资源了, 此时ticket=48
//打印卖第48张票。ticket--  tiket=47
//线程1又抢到循环
//现在的情况是:有可能两个线程同时进入到while循环
//
class MySync2 implements Runnable {
    int ticket = 500;
    //对这个run方法加了锁 就意味着只有一个线程进入到run方法中
    //其他线程都在run方法外面等待
    @Override
    public  void run() {
        //能不能对循环加锁?不能 因为循环加锁以后,还是一个线程循环完,没有任何意义

        while (true) {//死循环
            //if语句加了锁以后
            //就意味着只有一个线程进入到if语句
            //假如线程1进入if语句了,线程2和线程3就会等待
            //线程1打印50 并--  ticket变量为49
            //线程2抢到了49 sout(49) tiket--  48
            //其他线程再抢!!!

            //核心业务 加了锁,只让一个线程进入,操作完以后。锁释放掉
            //然后这三个线程再抢。还只能进一个,再操作核心业务
            synchronized (this) {//只能让一个线程进入操作,其他线程在外面等待排队
                if (ticket > 0) {
                    //线程具有抢占式的运行
                    //咱们有没有可能,线程3进入到if语句
                    //此时线程1也进入到if语句了
                    //线程3去打印 卖出了50张票
                    //在线程1里面  ticket=50
                    //线程3又抢到ticket-- 又进入到循环了  ticket = 49
                    //线程3又抢到了ticket-- 又进入倒循环 ticket=48
                    //线程1又抢到资源要执行,执行输出语句  tiekct=50
                    System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票");
                    ticket--;
                } else {
                    System.out.println("买完了");
                    break;//终止循环!!!
                }
            }
        }
    }
}
public class Demo3 {
    public static void main(String[] args) {
        MySync2 mySync = new MySync2();
        //这三个线程
        Thread thread1 = new Thread(mySync, "线程1");
        thread1.start();
        Thread thread2 = new Thread(mySync, "线程2");
        thread2.start();
        Thread thread3 = new Thread(mySync, "线程3");
        thread3.start();

        //为啥都是线程1卖出去的票?
        //很巧  线程1抢到执行权了,进入到run方法中
        //线程2和线程3在外面等着。
        //一个循环进来以后,把循环全部执行完!!!
        //会出现一家独大的情况!!!也是不符合咱们生活场景的!!!
        //咋解决?咱们 不能方法中加锁,在其他地方加锁


    }
}

线程就是这样,不可控制,但是可以加锁。让他可控制。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值