线程的初步使用

什么是线程?

java中,创建线程类就两个途径。实现Runnable接口,扩展Thread类。一般基于单继承多接口的原因,推荐使用Runnable接口!运行中的进程切换叫做“上下文切换”
最简单的线程例子
class ThreadDemo{
    public static void main(String[] args){
        new NewThread();
        try{
//主线程执行的代码
            for (int i= 5; i>0; i++){
                System.out.println("Main Thtrad :" +i);
            }
        } catch (Exception e){
            System.out.println("Main thread interruped.");
        }
        System.out.println("Main thred exiting.");
    }
}
class NewThread implements Runnable{
    Thread t;
    NewThread(){
        t = new Thread(this, "Demo Thread");
        System.out.println("Child thread :" + t);
        t.start();
    }
    @Override
    public void run() {
        try{
//子线程执行的代码
            for (int i=5 ; i>0; i++){
                System.out.println("Child Thread:"+ i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Exiting child thred");
        }
    }
}


这个功能只是简单的实现了主线程和子线程互相交替打印字符串到控制台的功能,并且死循环的运行下去。
运行结果:
会不断互相交替打印"Child Thread i" 和 "Main Thtrad i",谁先谁后,不固定!
看了以上代码会发现一个疑惑的地方,线程的run()到底什么时间执行。
其实,线程运行start()方法后,线程被允许可以执行线程类中的run()方法。该方法不用我们调用,程序会自己执行。但是具体什么时间执行,主线程和子线程的执行的先后顺序,都是电脑cpu自动选择的结果。所以会出现交替打印的效果。


线程的结束?

一般我们都希望主线程比子线程晚结束。这样可以进行释放资源等操作!这里我们要用到join()方法!join()是等待一个线程终止。线程还有一个isAlive()方法,返回值为boolearn,判断该线程是否正在执行,是返回true,否返回false
看下面一个例子
class NewMoreThread implements Runnable{
    Thread t;
    String name;
    NewMoreThread(String threadName){
        name = threadName;
        t = new Thread(this, name);
        System.out.println("New thread" + t);
        t.start();
    }
    @Override
    public void run() {
        try{
            for (int i=5 ; i>0; i--){
                System.out.println(name +":"+ i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println(name +"interruped.");
        }
        System.out.println(name + "exiting.");
    }
}
class JoinDemo{
    public static void main(String[] args){
        NewMoreThread ob1 =new NewMoreThread("One");
        NewMoreThread ob2 =new NewMoreThread("Two");
        NewMoreThread ob3 =new NewMoreThread("Three");
        System.out.println("Thread One os alive" + ob1.t.isAlive());
        System.out.println("Thread Two os alive" + ob2.t.isAlive());
        System.out.println("Thread Three os alive" + ob3.t.isAlive());
        try{
            System.out.println("Waiting for threads to finish.");
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (Exception e){
            System.out.println("Main thread interruped.");
        }
        System.out.println("Thread One is alive:" + ob1.t.isAlive());
        System.out.println("Thread Two is alive:" + ob2.t.isAlive());
        System.out.println("Thread Three is alive:" + ob3.t.isAlive());
    }
}
打印结果:
New threadThread[Two,5,main]
New threadThread[Three,5,main]
One:5
Thread One os alivetrue
Two:5
Thread Two os alivetrue
Thread Three os alivetrue
Waiting for threads to finish.
Three:5
Three:4
One:4
Two:4
Two:3
Three:3
One:3
Three:2
One:2
Two:2
One:1
Three:1
Two:1
Disconnected from the target VM, address: '127.0.0.1:62114', transport: 'socket'
Twoexiting.
Threeexiting.
Oneexiting.
Thread One is alive:false
Thread Two is alive:false
Thread Three is alive:false
你会发现,三个线程都结束的时,才会执行最后的三个打印控制台操作!


线程的运行顺序?

很多人就想到,如果是多个线程一起运行,能不能手动控制运行的先后顺序。答案是不能绝对控制,线程的运行顺序和很多因素都有关系!只能提高某些线程获取cpu资源执行代码的几率!
线程通过;setPriority(Thread.MAX_PRIORITY);给线程赋予优先级。MAX_PRIORITY默认值是5.最大值是10,最小值是1,值越大,优先级越大。
先给大家一个例子!
class Clicker implements Runnable{
    int click = 0;
    Thread t;
    private volatile boolean running = true;
    public Clicker(int p){
        t = new Thread(this);
        t.setPriority(p);
    }
    @Override
    public void run() {
        while (running){
            click++;
        }
    }
    public void stop(){
        running = false;
    }
    public void start(){
        t.start();
    }
}
class HiLoPri{
    public static void main (String[] args){
        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        Clicker hi = new Clicker(Thread.NORM_PRIORITY + 2 );
        Clicker lo = new Clicker(Thread.NORM_PRIORITY - 2);
        hi.start();
        lo.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Main thread interrupted.");
        }
        lo.stop();
        hi.stop();
        try {
            hi.t.join();
            lo.t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterrupetedException caught");
        }
        System.out.println("Low - priority thread:" +lo.click);
        System.out.println("High - priority thread:" +hi.click);
    }
}
运行结果:
High - priority thread:311376165
Low - priority thread:141875148
很明显,high的运行次数远大于low!因为执行的概率高!


当使用多线程时,同时操作一个对象时,可能出现重复操作的现象,造成输出结果混乱
线程同步
class CallMe{
     void call(String msg){
        System.out.println("[" +msg);
        try{
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Intrttupted");
        }
        System.out.println("]");
    }
}
class Caller implements Runnable{
    String msg;
    CallMe target;
    Thread t;
    public Caller(CallMe targ, String s){
        target = targ;
        msg = s;
        t = new Thread(this);
        t.start();
    }
    @Override
    public void run() {
        target.call(msg);
    }
}
class Synch {
    public static void main (String[] args){
        CallMe target = new CallMe();
        Caller ob1 = new Caller(target, "Hello");
        Caller ob2 = new Caller(target,"Synchronized");
        Caller ob3 = new Caller(target,"world");
        try{
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


运行结果会出现:
Hello[Synchronized{world]]]类似这种混乱的结果。此时,为了防止这种现象发生,我们希望每次只有一个线程在执行该方法,而其他线程不能进入这方法中。这时候,就要用synchronized关键字。用该关键字修饰的方法和类,一次只有一个线程可以使用或创建,
修改后的代码如下!
class CallMe{
    synchronized void call(String msg){
        System.out.println("[" +msg);
        try{
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Intrttupted");
        }
        System.out.println("]");
    }
}
class Caller implements Runnable{
    String msg;
    CallMe target;
    Thread t;
    public Caller(CallMe targ, String s){
        target = targ;
        msg = s;
        t = new Thread(this);
        t.start();
    }
    @Override
    public void run() {
        target.call(msg);
    }
}
class Synch {
    public static void main (String[] args){
        CallMe target = new CallMe();
        Caller ob1 = new Caller(target, "Hello");
        Caller ob2 = new Caller(target,"Synchronized");
        Caller ob3 = new Caller(target,"world");
        try{
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程的通信

人门在设计线程通信的时候,总是希望生产者每生产一个资源,消费者就来消耗资源。线程的执行顺序是不可控的,假如生产者线程执行了5次,消费者线程才执行了一次,这种结果不是我们想要的,为了解决这种问题,我们要用到线程的另外三个方法!
wait() :挂起线程
notify() :运行上一个被挂起的线程
notifyAll():运行被挂起的所有线程
没有控制的代码:
class Q {
    int n;
    synchronized  int get(){     
            System.out.println("Got:" +n);
            return n;
        }
    synchronized void put(int n){
        this.n = n;
        System.out.println("Put:" +n);
    }
}
class Producer implements Runnable{
    Q q;
    Producer(Q q ){
        this.q = q;
        new Thread(this, "Producer").start();
    }
    @Override
    public void run() {
        int i= 0;
        while(true){
            q.put(i++);
        }
    }
}
class Consumer implements Runnable{
    Q q ;
    Consumer(Q q){
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    @Override
    public void run() {
        while(true){
            q.get();
        }
    }
}
class PC{
    public static void main(String[] args ){
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control -c to stop.");
    }
}
输出结果为:
Put:0
Put:1
Put:2
Put:3
Put:4
Put:5
Got:5
Put:6
Put:7
Put:8
Put:9
Put:10
Put:11
Put:12
Put:13
优化后的代码:
class Q {
    int n;
    boolean valueSet = false;
    synchronized  int get(){
        if(!valueSet){
            try{
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Got:" +n);
            return n;
        }
        valueSet = false;
        notify();
        return n;
    }
    synchronized void put(int n){
        if (valueSet){
            try{
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.n = n;
        valueSet = true;
        System.out.println("Put:" +n);
        notify();
    }
}
class Producer implements Runnable{
    Q q;
    Producer(Q q ){
        this.q = q;
        new Thread(this, "Producer").start();
    }

    @Override
    public void run() {
        int i= 0;
        while(true){
            q.put(i++);
        }
    }
}
class Consumer implements Runnable{
    Q q ;
    Consumer(Q q){
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    @Override
    public void run() {
        while(true){
            q.get();
        }
    }
}
class PC{
    public static void main(String[] args ){
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control -c to stop.");
    }
}
运行结果为:
Put:1
Got:1
Put:2
Got:2
Put:3
Got:3
Put:4
Got:4
Put:5
Got:5
Put:6
Got:6
Put:7
Got:7
Put:8
Got:8

实现人为控制的挂起进程:

class CommunicationThread implements  Runnable{
    String name;
    Thread t;
    boolean suspendFlag;
    CommunicationThread(String name){
        this.name = name;
        t =new Thread(this.name);
        System.out.println("New thread:" + t);
        suspendFlag = false;
        t.start();
    }
    @Override
    public void run() {
        try{
            for (int i= 0 ; i>0 ; i--){
                System.out.println(name +":"+i);
                Thread.sleep(1000);
                synchronized (this){
                    while (suspendFlag){
                        wait();
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name +"exiting.");
    }
    void mySuspend(){
        suspendFlag = true;
    }
    synchronized  void myResume(){
        suspendFlag = false;
        notify();
    }
}
class SuspendResume{
    public static void main(String[] args ){
        CommunicationThread ob1 =new CommunicationThread("One");
        CommunicationThread ob2 = new CommunicationThread("Two");
        try{
            Thread.sleep(1000);
            ob1.mySuspend();
            System.out.println("Suspending thread One");
            Thread.sleep(1000);
            ob1.myResume();
            System.out.println("Resuming thread One");
            Thread.sleep(1000);
            ob2.mySuspend();
            System.out.println("Suspending thread Two");
            Thread.sleep(1000);
            ob2.myResume();
            System.out.println("Resuming thread Two");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try{
            System.out.println("Waiting for threads to finish.");
            ob1.t.join();
            ob2.t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Main thread exiting.");
    }
}

第一次全面了解线程,哪里描述不当之处希望网友可以指出,让我学习更深入,在这里先谢过!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值