Java语法-线程与多线程

1、线程调度有哪些调度方式?

分时调度;
抢占式调度;

2、什么叫主线程?

执行主方法-main方法 的线程;

3、如何利用Thread类来实现多线程?

新线程程序需要放到自己创建的Thread子类的run方法中;
在主程序中,用新线程类的对象调用 start方法 可以跑其中的 run 方法;

public class MyThread extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("ZiThread:" + i);
        }
    }
}
public class test {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("main:" + i);
        }
    }
}

4、调用mt.start() 和 mt.run() 有什么区别?

要是调用 mt.run() 那么就是单线程程序;
main方法在一个栈空间中,mt.run()会在原来的栈中压入;
如果调用mt.start(),那么系统会开辟一个新的栈空间
CPU有选择栈空间的权利,可以执行任意栈空间的方法;

5、线程的名称是如何规定的?

主线程的名称叫做main;
新线程从Thread-0开始;

6、获取当前系统使用的线程是什么方法?

Thread.currentThread()

7、可以给新线程起名吗?

可以;

8、sleep方法有什么用?如何调用 sleep方法?

(1) sleep方法可以让线程停止一段时间;
(2) sleep方法是类的方法,用Thread类调用即可;

9、如何通过实现Runnable接口的方式启动多线程?

Runnable的实现类(重写run方法);
new 一个 Runnable 实现类对象;
这个实现类对象作为参数传入 Thread()当中构造一个Thread对象;
这种方法第一印象很好;

		RunnableImpl r = new RunnableImpl();
        Thread t = new Thread(r);
        t.start();

10、Runnable接口实现方式创建多线程的有优点是什么?

(1)避免单继承的局限性,Runnable是接口,可实现多个接口,而Thread是类,一个实现类只能继承它一个类,继承它之后就不能继承其他的类;
(2)降低了程序的耦合性,线程的功能是 Runnable实现类的方法的,线程的开启是Thread对象的事情;我一个产品做好了,直接使用在下一个产品中,这样叫降低了耦合性。如果一个类既要重写run方法,它的对象又要调用start方法,这样的话就有很高的耦合性;

11、什么是耦合性?我们应该追求高耦合性还是低耦合性?

耦合性是模块间关联程度的度量;
软件设计中追求高内聚,低耦合;

12、如何通过匿名内部类实现线程的创建?

new 父类/接口(){重写run方法}

 Runnable r = new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "-" + i);
                }
            }
        };
        new Thread(r).start();

13、举例说明说明是线程安全问题?

电影院:
一个窗口卖100张电影票,从编号1卖到100没有问题;
三个窗口卖100张电影票,从编号1卖到100产生问题,例如两个窗口同时卖编号第20的票;
多线程访问了共享的数据,就会出现线程安全问题

14、多线程卖票如何代码实现?即多线程如何访问共享数据?

让一个线程访问共享数据的时候,无论是否失去了CPU的执行权,让其他线程只能等待;

15、如何使用同步代码块实现卖票线程安全问题?

synchronized(锁对象){访问共享数据的代码}

public class RunnableImpl implements Runnable {

    private int ticket = 100;

    Object obj = new Object();
    @Override
    public void run() {


        while (true){
            synchronized (obj){
                if (ticket > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "-->正在卖" + ticket + "张票");
                    ticket--;
                }
            }
        }
    }
}
public class test {
    public static void main(String[] args){
        RunnableImpl run = new RunnableImpl();

        // 创建一个实现类传到三个线程里面
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);

        t0.start();
        t1.start();
        t2.start();
    }
}

16、同步代码块技术实现线程安全的原理是什么?

当某线程抢到CPU执行权的时候,遇到 synchronized 会检查是否有锁对象;
有锁对象就执行同步代码块里面的内容,等到执行完毕就归还锁对象;
没有锁对象就进入阻塞状态,等带锁对象被其他线程归还;

17、同步方法实现卖票多线程安全问题的代码实现是怎样的?

定义一个同步方法,同步方法的特征就是在方法修饰符中多一个 synchronized;

public class RunnableImpl implements Runnable {

    private int ticket = 100;

    @Override
    public void run(){
        while(true){
            payTicket();
        }
    }
	
	public synchronized void payTicket(){
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->正在卖" + ticket + "张票");
            ticket--;
        }
    }
}

18、同步方法和同步代码块有什么关系?

同步方法也用到了锁;
同步代码块用到的锁是自己定义的;
同步方法用到的锁实际上是实现类对象 —— new RunnableImpl();
下面的代码片段等价与上面的同步方法;

public /*synchronized*/ void payTicket(){
        synchronized (this){
            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "-->正在卖" + ticket + "张票");
                ticket--;
            }
        }
    }

19(了解)、如果同步方法是静态同步方法,那么锁对象还能是this吗?不是this的话是什么?

静态同步方法用静态变量(所谓静态的用静态的);
锁对象不能是 this , 因为 this 是创建对象后产生,静态方法优先于对象进行编译
静态同步方法的锁对象是本类的class属性 —— RunnableImpl.class;

20、如何使用lock锁解决线程安全问题?

使用Lock接口的实现类 ReentrantLock 的对象;
在可能出现线程安全问题的代码前获取锁,lock();
在可能出现线程安全问题的代码后释放锁,unlock();

public class RunnableImpl implements Runnable {

    private int ticket = 100;

    Lock l = new ReentrantLock(); // 多态

    @Override
    public void run(){
        while(true){

            l.lock();

            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                    } catch (InterruptedException e) {
                    e.printStackTrace();
                    }
                System.out.println(Thread.currentThread().getName() + "-->正在卖" + ticket + "张票");
                ticket--;
            }

            l.unlock();
        }
    }

21(了解)、线程有哪些状态?
操作系统的线程的状态图

22、等待与唤醒机制代码如何实现?

同步代码块 + 锁对象.wait() / notify()

public class test2 {
    public static void main(String[] args) {

        Object obj = new Object();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj){
                    System.out.println("顾客告诉老板购买包子的数量");
                    try {                                   // 在同步代码块中写 obj.wait()
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("包子很好吃");
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj){
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("老板告诉顾客包子做好了");
                    obj.notify();
                }
            }
        }).start();
    }
}

23、实现如下等待与唤醒实例
在这里插入图片描述

public class BaoZi {

    public String pi;

    public String xian;

    boolean flag = false;
}
public class BaoZiPu extends Thread{

    public int count = 0;

    private BaoZi bz;

    public BaoZiPu(){

    }

    public BaoZiPu(BaoZi bz){
        this.bz = bz;
    }

    @Override
    public void run() {

        while(true){
            synchronized (bz){
                if(bz.flag){
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                else {
                    if(count % 2 == 0){
                        bz.pi = "薄皮";
                        bz.xian = "素馅";
                    }
                    else {
                        bz.pi = "冰皮";
                        bz.xian = "肉馅";
                    }
                    count++;
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("包子铺生产好了" + bz.pi+bz.xian+"的包子");
                    bz.flag = true;
                    bz.notify();
                }
            }
        }
    }
}
public class ChiHuo extends Thread {

    private BaoZi bz;

    public ChiHuo() {
    }

    public ChiHuo(BaoZi bz){
        this.bz = bz;
    }

    @Override
    public void run() {
        while (true){
            synchronized (bz){
                if(bz.flag){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("吃货在吃"+bz.pi+bz.xian+"的包子");
                    bz.flag = false;
                    bz.notify(); // 吃货吃完了唤醒包子铺做包子
                }
                else {
                    try {
                        bz.wait(); // 没有包子的时候,吃货处于等待状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
public class test3 {
    public static void main(String[] args) {
        BaoZi bz = new BaoZi();

        BaoZiPu bzp = new BaoZiPu(bz);
        ChiHuo ch = new ChiHuo(bz);

        bzp.start();
        ch.start();
    }

这是一个很好的学习借鉴例题;
在测试类中创建好包子对象,传入其他类中作为对象使用

24、如果一个线程里面既有wait(),又有notify(),它们会互相通信吗?

wait(),notify() 方法是线程间通讯的方法,并不是线程内通信的方法;
wait() 指的是当前线程释放锁,让出CPU;
notify() 是唤醒其他线程,并不是唤醒本线程;
一个线程里面既有wait(),又有nofity(),这说明这个线程会先notify(),然后再wait();

25、线程池如何使用?

1、创建线程池
ExecutorService es = Executors.newFixedThreadPool(3); // 类名+静态方法名+var;
2、创建Runnable接口的实现类,重写run方法;
3、线程池对象调用submit方法,传入Runnable接口实现类的对象;

26、线程池是什么?作用是什么?

线程池实际上就是一个装很多线程的容器;
线程池的作用是在重复使用线程时,提高时间利用率;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值