java基础学习笔记6

java基础学习笔记6

线程

Cpu速度比较快,看起来是多线程,实际上,在一个时间点上,只有一个线程在运行。

进程:静态概念。

线程:一个进程里面有个主线程,叫main方法。

一个程序里面不同的执行路径。

通过java.lang.Thread类实现。

实现方法:

1.实现Runnable接口

public class thtest {
    public static void main(String[] args) {
        t1 t1=new t1();
        t1.run();

//        Thread t=new Thread(t1);
//        t.start();

        for(int i=0;i<5;i++){
            System.out.println("主线程"+i);
        }
    }
}


class t1 implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println("新线程"+i);
        }
    }
}

2.从Thread类继承

继承以后,本身就是一个Thread了,就不用了new一个Thread了。

public class thtest {
    public static void main(String[] args) {
        t1 t1=new t1();
        t1.start();
        for(int i=0;i<5;i++){
            System.out.println("主线程"+i);
        }
    }
}


class t1 extends Thread{
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println("新线程newnewnew"+i);
        }
    }
}

run和start区别

调用start,会交替运行主子线程。

image-20201001135515858

调用run,会先走子线程,在回主线程。

image-20201001135426490

哪种比较好?

实现Runnable比较好。

因为继承只能继承一个。继承以后就不灵活了。

线程状态

new 出来,然后start()就绪准备,通过cpu调度,有空就运行一下这个子线程。

子线程运行时,随时被cpu又调成start状态。

子线程运行期间,很有可能发生阻塞,进入阻塞状态,就呆在那里不运行。阻塞解除以后回到start状态。

线程控制的基本方法

1.isAlive()

new出来没start也是死的。

线程结束了,也是死的。

就绪,阻塞,都是活的。

2.getPriority setPriority

优先级,优先级越高,得到的cpu分配的时间片越多

范围:1-10 默认为5

package com.ufo.eight;

import java.util.Date;

public class thtest {
    public static void main(String[] args) {
        T1 t1 = new T1();
        Thread th1=new Thread(t1);
        th1.setPriority(10);

        T2 t2 = new T2();
        Thread th2=new Thread(t2);


        th1.start();th2.start();

    }
}


class T1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("子线程11111111111" + i);

        }
    }
}


class T2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("子线程二二二二二" + i);

        }
    }
}

结果:可以看出,子线程1设置优先级以后,前面部分大部分是子线程1,但没有绝对把子线程2杀死,还有有点子线程2在运行的。

结果:
子线程111111111110
子线程111111111111
子线程111111111112
子线程111111111113
子线程111111111114
子线程111111111115
子线程111111111116
子线程111111111117
子线程111111111118
子线程111111111119
子线程1111111111110
子线程1111111111111
子线程1111111111112
子线程1111111111113
子线程1111111111114
子线程1111111111115
子线程1111111111116
子线程1111111111117
子线程1111111111118
子线程1111111111119
子线程1111111111120
子线程1111111111121
子线程1111111111122
子线程1111111111123
子线程二二二二二0
子线程二二二二二1
子线程1111111111124
子线程二二二二二2
子线程二二二二二3
子线程二二二二二4
子线程二二二二二5
子线程二二二二二6
子线程二二二二二7
子线程二二二二二8
子线程二二二二二9
子线程1111111111125
子线程二二二二二10
子线程1111111111126
子线程1111111111127
子线程1111111111128
子线程1111111111129
子线程1111111111130
子线程1111111111131
子线程1111111111132
子线程1111111111133
子线程1111111111134
子线程1111111111135
子线程1111111111136
子线程1111111111137
子线程二二二二二11
子线程二二二二二12
子线程二二二二二13
子线程二二二二二14
子线程二二二二二15
子线程二二二二二16
子线程二二二二二17
子线程二二二二二18
子线程二二二二二19
子线程二二二二二20
子线程1111111111138
子线程1111111111139
子线程1111111111140
子线程1111111111141
子线程1111111111142
子线程1111111111143
子线程1111111111144
子线程1111111111145
子线程1111111111146
子线程1111111111147
子线程1111111111148
子线程1111111111149
子线程1111111111150
子线程1111111111151
子线程1111111111152
子线程1111111111153
子线程1111111111154
子线程1111111111155
子线程1111111111156
子线程1111111111157
子线程1111111111158
子线程1111111111159
子线程1111111111160
子线程1111111111161
子线程1111111111162
子线程1111111111163
子线程1111111111164
子线程1111111111165
子线程1111111111166
子线程1111111111167
子线程1111111111168
子线程1111111111169
子线程1111111111170
子线程1111111111171
子线程1111111111172
子线程1111111111173
子线程1111111111174
子线程1111111111175
子线程二二二二二21
子线程1111111111176
子线程1111111111177
子线程1111111111178
子线程1111111111179
子线程1111111111180
子线程1111111111181
子线程1111111111182
子线程1111111111183
子线程1111111111184
子线程1111111111185
子线程1111111111186
子线程1111111111187
子线程1111111111188
子线程1111111111189
子线程1111111111190
子线程1111111111191
子线程1111111111192
子线程1111111111193
子线程1111111111194
子线程1111111111195
子线程二二二二二22
子线程二二二二二23
子线程1111111111196
子线程1111111111197
子线程1111111111198
子线程1111111111199
子线程二二二二二24
子线程二二二二二25
子线程二二二二二26
子线程二二二二二27
子线程二二二二二28
子线程二二二二二29
子线程二二二二二30
子线程二二二二二31
子线程二二二二二32
子线程二二二二二33
子线程二二二二二34
子线程二二二二二35
子线程二二二二二36
子线程二二二二二37
子线程二二二二二38
子线程二二二二二39
子线程二二二二二40
子线程二二二二二41
子线程二二二二二42
子线程二二二二二43
子线程二二二二二44
子线程二二二二二45
子线程二二二二二46
子线程二二二二二47
子线程二二二二二48
子线程二二二二二49
子线程二二二二二50
子线程二二二二二51
子线程二二二二二52
子线程二二二二二53
子线程二二二二二54
子线程二二二二二55
子线程二二二二二56
子线程二二二二二57
子线程二二二二二58
子线程二二二二二59
子线程二二二二二60
子线程二二二二二61
子线程二二二二二62
子线程二二二二二63
子线程二二二二二64
子线程二二二二二65
子线程二二二二二66
子线程二二二二二67
子线程二二二二二68
子线程二二二二二69
子线程二二二二二70
子线程二二二二二71
子线程二二二二二72
子线程二二二二二73
子线程二二二二二74
子线程二二二二二75
子线程二二二二二76
子线程二二二二二77
子线程二二二二二78
子线程二二二二二79
子线程二二二二二80
子线程二二二二二81
子线程二二二二二82
子线程二二二二二83
子线程二二二二二84
子线程二二二二二85
子线程二二二二二86
子线程二二二二二87
子线程二二二二二88
子线程二二二二二89
子线程二二二二二90
子线程二二二二二91
子线程二二二二二92
子线程二二二二二93
子线程二二二二二94
子线程二二二二二95
子线程二二二二二96
子线程二二二二二97
子线程二二二二二98
子线程二二二二二99

3.Thread.sleep

暂停一小会儿

注意他是静态方法,传入毫秒数,记得抛异常,中断异常

不能在run上面抛出异常,因为重写存的方法抛出的异常不能和重写之前不一样。



import java.util.Date;

public class thtest {
    public static void main(String[] args) {
        T1 t1=new T1();
        t1.start();
        try {
            Thread.sleep(5000);

        } catch (InterruptedException e) {

        }
        t1.interrupt();
    }
}


class T1 extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println("子线程在运行"+new Date());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("子线程被打断了");
                return;
            }

        }
    }
}

image-20201001142019052

关闭一个线程,建议不适用interrupt,万一打开一个资源没关闭,太粗暴了。

推荐办法:使用标志位,让子线程自己结束。

image-20201001142617568

4.join 合并

把子线程合并到当前线程。相当如方法调用。和run()一个结果。需要把子线程执行完后当前线程才能继续执行。

public class thtest {
    public static void main(String[] args) {
        T1 t1=new T1();
        t1.start();
        try {
            t1.join();
        } catch (InterruptedException e) {
        }

        for (int i=0;i<5;i++){
            System.out.println("主线程"+i);
        }
    }
}


class T1 extends Thread{
    @Override
    public void run() {
        for (int i=0;i<5;i++){
            System.out.println("子线程enwewnewn"+i);
        }
    }
}

image-20201001143335325

5.yeild 让出cpu,让其他线程先运行,当前线程进入就绪队列,等待调度

public class thtest {
    public static void main(String[] args) {
        T1 t1 = new T1();
        T1 t2 = new T1();
        t1.start();t2.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程" + i);
        }
    }
}


class T1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程enwewnewn" + i);
            if(i==3){
                yield();
            }
        }
    }
}

image-20201001143710092

6.wait 当前线程对象进入wait pool

7.notify notifyAll

唤醒wait pool里面的一个/所有等待线程

线程同步

遇到问题:同时访问同一资源,会遇到问题。

synchronized //在一个线程执行过程中,不会被另一个线程打断

package com.ufo.eight;

public class TestSync implements Runnable {
    Timer timer = new Timer();

    public static void main(String[] args) {
        TestSync test = new TestSync();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        t2.start();
    }

    public void run() {
        timer.add(Thread.currentThread().getName());
    }
}

class Timer {
    private static int num = 0;

    public synchronized void add(String name) {
//        synchronized (this) {
        num++;
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
        }
        System.out.println(name + ", 你是第" + num + "个使用timer的线程");
//        }
    }
}

死锁:
假如线程A执行过程中,需要锁定对象C1,再锁C2。

接下来另一个线程B,需要先锁C2,再锁C1。

假如这两个线程AB同时运行,A先锁住C1,B先锁住C2,那么这两个线程的另一个需要锁的对象都被对方锁了,导致两个线程都执行不下去。这就是死锁。

程序模拟:

package com.ufo.eight;

public class TestDeadLock implements Runnable {
    public int flag = 1;
    //注意这里!!!static!!静态的!!所以不管new多少个TestDeadLock出来,他的01 02对象只有两个!  所以在加锁时能模拟出死锁的情况。
    static Object o1 = new Object(), o2 = new Object();
    public void run() {
        System.out.println("flag=" + flag);
        if(flag == 1) {
            synchronized(o1) {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized(o2) {
                    System.out.println("1");
                }
            }
        }
        if(flag == 0) {
            synchronized(o2) {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized(o1) {
                    System.out.println("0");
                }
            }
        }
    }

    public static void main(String[] args) {
        TestDeadLock td1 = new TestDeadLock();
        TestDeadLock td2 = new TestDeadLock();
        td1.flag = 1;
        td2.flag = 0;
        Thread t1 = new Thread(td1);
        Thread t2 = new Thread(td2);
        t1.start();
        t2.start();

    }
}

image-20201001164258828程序一直运行,不会结束。。

如何解决?把锁的粒度加粗。就是不要锁那么细,锁整个过程就好了啊。

public class TT implements Runnable {
    int b = 100;

    public synchronized void m1() throws Exception{
        System.out.println("333");
        b = 1000;
        System.out.println("444等待5秒");
        Thread.sleep(5000);
        System.out.println("555");
        System.out.println("b = " + b);
    }

    public synchronized void m2() throws Exception {
        System.out.println("111等待2.5");
        Thread.sleep(2500);
        System.out.println("222");
        b = 2000;
}

    public void run() {
        try {
            m1();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        TT tt = new TT();
        Thread t = new Thread(tt);
        t.start();
        tt.m2();
        System.out.println(tt.b);
    }
}

结果:

111 等待2.5
222
2000
333
444 等待5秒
555
b = 1000

只去掉m1的锁:

111
333
444 等待2.5
222
2000 等待2.5
555
b = 2000

只去掉m2的锁:

111
333
444 等待2.5
222
2000 等待2.5
555
b = 2000

去掉m1,m2的锁:

111
333
444 等待2.5
222
2000 等待2.5
555
b = 2000

所以如果两个方法都改了同一个值,那么这两个方法应该加synchronize

生产者消费者问题

定义篮子,定义馒头,定义生产者,定义消费者。

其中,生产者,消费者都是线程。

篮子有push和pop方法。生产者调用push,消费者调用pop。

生产生放进去的时候判断是否是满的,满的就wait,去除锁。

消费者拿出来,判断是否为空,空就wait,去除锁。

当篮子满了,消费者消费以后,就唤醒所有锁,生产者再次push。

package com.ufo.eight;


public class ProducerConsumer {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer p = new Producer(ss);
        Consumer c = new Consumer(ss);
        new Thread(p).start();
        new Thread(p).start();
//        new Thread(p).start();
        new Thread(c).start();
    }
}

class WoTou {
    int id;
    WoTou(int id) {
        this.id = id;
    }
    public String toString() {
        return "WoTou : " + id;
    }
}

class SyncStack {
    int index = 0;
    WoTou[] arrWT = new WoTou[6];

    public synchronized void push(WoTou wt) {
        while(index == arrWT.length) {
            try {
                this.wait();
                
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll();
        arrWT[index] = wt;
        index ++;
    }

    public synchronized WoTou pop() {
        while(index == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll();
        index--;
        return arrWT[index];
    }
}

class Producer implements Runnable {
    SyncStack ss = null;
    Producer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for(int i=0; i<20; i++) {
            WoTou wt = new WoTou(i);
            ss.push(wt);
            System.out.println("生产了:" + wt);
            try {
                Thread.sleep((int)(Math.random() * 200));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {
    SyncStack ss = null;
    Consumer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for(int i=0; i<60; i++) {
            WoTou wt = ss.pop();
            System.out.println("消费了: " + wt);
            try {
                Thread.sleep((int)(Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

wait和sleep区别

wait是object提供的方法。

sleep是thread提供的方法。

只有在锁定方法里面才能用wait。

wait时别的线程可以访问锁定对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值