多线程part1

写在前面:最近在学习多线程的部分,尝试写一写博客,整理自己的思路,有理解不到位的欢迎指正,共同进步。

线程的创建

线程的创建有两种方式:
1、直接new Thread类
2、实现Runnable接口

    Thread thread = new Thread() {
        @Override
        public void run() {
            // 保证线程一直在运行
            while (true) {
                try {
                    // 睡1秒
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread:" + Thread.currentThread().getName());
            }
        }
    };
    thread.start();

    Thread thread2 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Runnable:" + Thread.currentThread().getName());
            }
        }
    });
    thread2.start();

代码会不停地打印两个线程的名称

thread:Thread-0
Runnable:Thread-1
Runnable:Thread-1
thread:Thread-0

思考题
如果new Thread的同时又实现了Runnable接口,分别重写不同run方法,会执行哪一个

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("runnable3");
        }
    };
    Thread thread3 = new Thread(runnable) {
        @Override
        public void run() { 
            System.out.println("thread3");
        }
    };
    thread3.start();

答案
Runnable相当于是Thread的父类,父类和子类都实现了run方法,子类会覆盖父类,所以输出是

thread3

传统的定时器

Java本身的定时器Timer通过新建一个定时器,实现一个定时任务来完成。

    new Timer().schedule(new TimerTask() {

        @Override
        public void run() {
            System.out.println("bombing");
        }
    }, 3000, 5000); //3s后爆炸,每隔5s爆炸
    //通过循环打印当前时间来观察爆炸时间
    while(true) {
        System.out.print(new Date().getSeconds() + " ");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

输入如下:

9 10 11 bombing
12 13 14 15 16 bombing
17 18 19 20 21 bombing

思考题
如果想要实现定时器,间隔2s和4s交替爆炸,应该怎样做

答案
常规定时器执行间隔时间在创建时已经设置好了,不符合要求。考虑在一个定时器内嵌套一个另一个定时器,这时怎样控制间隔时间?利用静态属性来控制,无论新建多少对象,静态属性始终只有一个。
代码如下:

    public class MyTimerTask extends TimerTask{
        private static int num = 1; // 静态属性,一个类只有一个值
        @Override
        public void run() {
            System.out.println("num=" + num++ + " " + new Date().getSeconds() + " bombing ");
            int count = num % 2;
            try {
                Thread.sleep(count);
                // 嵌套一个定时任务
                new Timer().schedule(new MyTimerTask(), count * 2000 + 2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
    // 主函数新建一个定时任务即可
    public static void main(String[] args) {
        new Timer().schedule(new MyTimerTask(), 2000);
    }

输出为:

num=1 14 bombing 
num=2 16 bombing 
num=3 20 bombing 
num=4 22 bombing 
num=5 26 bombing 
num=6 28 bombing 

线程互斥

下面代码实现了一个简单的字符串输出功能,一直不停的输出“zhangSan”和“liSi”

public class SynchronizedThread {

    public static void main(String[] args) {
        while (true) {
            new Thread() {
                @Override
                public void run() {
                    output("zhangSan");
                }
            }.start();

            new Thread() {
                @Override
                public void run() {
                    output("liSi");
                }
            }.start();
        }
    }

    public static void output(String str) {
        for (int i = 0; i < str.length(); i++) {
            System.out.print(str.charAt(i));
        }
        System.out.println();
    }
}

从输出结果中发现了异常的结果

zhangSaliSi
zhanglliSi
zhangSan

输出的顺序发生了混乱,什么导致了这种情况呢?
一个线程正在输出的过程中,资源被另一个线程占用导致当前线程等待,于是一个字符串的打印一部分又开始打印另一个字符串,便出现了乱码。如果涉及到银行账户余额的变化时,一个线程对余额的增加还没处理完成,另一个线程对余额进行扣除,就会出现严重的资金问题。所以需要线程互斥。在这里我们用加锁的方式来保证线程的原子性。
可以对类进行加锁,也可以对代码块加锁,关键字synchronized。

    public static synchronized void output2(String str) {
        for (int i = 0; i < str.length(); i++) {
            System.out.print(str.charAt(i));
        }
        System.out.println();
    }

    public static void output3(String str) {
        synchronized (SynchronizedThread.class) {
            for (int i = 0; i < str.length(); i++) {
                System.out.print(str.charAt(i));
            }
            System.out.println();
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_35640274/article/details/81175878