javaSE线程基础

一、创建线程的方法

1.继承Thread

public class 继承Thread {
    public static void main(String[] args){
        T1 t1=new T1();
        T2 t2=new T2();
        t1.start();
        t2.start();
    }
}
class T1 extends Thread {
    public void run(){
        for(int i=0;i<5;i++) {
            System.out.println("你是谁啊");
        }
    }
}
class T2 extends Thread {
    public void run(){
        for(int i=0;i<5;i++) {
            System.out.println("我是线程");
        }
    }
}

运行结果

 需要注意:线程并不是连续且顺序执行的,哪个线程执行主要看CPU给每个线程分配到的时间

2.实现Runnable接口

public class 实现Runnable {
    public static void main(String[] args){
        //创建一个线程要执行的任务
        T t=new T();
        //创建一个线程
        Thread thread=new Thread(t);
        //启动线程
        thread.start();
    }
}
class T implements Runnable{

    @Override
    public void run() {
        System.out.println(1111111);
    }
}

 运行结果:

 3.实现Callable接口

public class 实现Callable {
    public static void main(String[] args){
        CallableTest callableTest=new CallableTest();
        FutureTask<String> futureTask=new FutureTask(callableTest);
        futureTask.run();
        try {
            String st=futureTask.get();
            System.out.println(st+"====");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
class CallableTest implements Callable<String>{

    @Override
    public String call() throws Exception {
        System.out.println("任务开始了");
        Thread.sleep(1000);
        return null;
    }
}

运行结果:

 这种创建线程方式需借助FutureTask类来实现

与实现Runnable接口的方式相比,可以在方法上抛出异常且有返回值

4.也可以通过匿名内部类的方式来创建线程

public class 匿名内部类的方式创建线程 {
    public static void main(String[] args){
        Thread thread=new Thread(){
            public void run(){
                System.out.println("我是线程");
            }
        };
        thread.start();
    }
}

这种方式等同于继承Thread

二、线程睡眠

Thread.sleep()方法可以令线程阻塞一段时间

public class 线程睡眠 {
    public static void main(String[] args){
        Thread thread=new Thread(){
            public void run(){
                Scanner sc=new Scanner(System.in);
                int f=sc.nextInt();
                while(f>=0){
                    System.out.println(f);
                    f--;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
    }
}

三、线程并发安全问题

两个或多个进程并发访问共享数据,共享数据的最终结果取决于进程运行的精确时序,这种情况称为竞争条件。为了防止竞争条件的发生,并发进程需要进行同步,也就是给共享资源安上一把锁(synchronized)

1.未加锁

public class 线程并发安全问题 {
    static Object o=new Object();
    public static void main(String[] args){
        Thread t1=new Thread("小龙女"){
            public void run(){
                getBean(Thread.currentThread().getName());
            }
        };
        Thread t2=new Thread("李莫愁"){
            public void run(){
                getBean(Thread.currentThread().getName());
            }
        };
        t1.start();
        t2.start();
    }
    public static void getBean(String name){
        System.out.println(name+"进入商场");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name+"挑衣服");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "进试衣间");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "试衣服");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "出试衣间");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name+"走出商场");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

很明显,商场可以多个人一起进入,挑选衣服与离开商场也是可以同时进行,但当商场只有一个试衣间时,是不能两个人同时进入试衣间的,这时这个试衣间内的活动就是我们所说的共享资源,为了让多人使用这个共享资源不会发生冲突,我们需要给共享资源加上一把锁

 2.加上锁

public class 线程并发安全问题 {
    static Object o=new Object();
    public static void main(String[] args){
        Thread t1=new Thread("小龙女"){
            public void run(){
                getBean(Thread.currentThread().getName());
            }
        };
        Thread t2=new Thread("李莫愁"){
            public void run(){
                getBean(Thread.currentThread().getName());
            }
        };
        t1.start();
        t2.start();
    }
    public static void getBean(String name){
        System.out.println(name+"进入商场");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name+"挑衣服");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (线程并发安全问题.class) {
            System.out.println(name + "进试衣间");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "试衣服");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "出试衣间");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(name+"走出商场");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}

运行结果

 当有线程在使用共享资源时,其他线程处于阻塞态,等待CPU给分配使用共享资源

四、加塞阻塞(插队)

当我们在打扫屋子时,我们需要先扫地,当地面扫干净后,我们才能拖地;而不能扫地和拖地一起进行或是先拖地后扫地,这时我们就需要做一个执行的顺序要求join()

public class 加塞阻塞or插队 {
    public static void main(String[] args){
        Thread t1=new Thread(){
            public void run(){
                for(int i=0;i<5;i++){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("我扫");
                }
                System.out.println("扫完了");
            }
        };
        Thread t2=new Thread(){
            public void run(){
                try {
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for(int i=0;i<5;i++){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("我拖");
                }
                System.out.println("拖完了");
            }
        };
        t1.start();
        t2.start();
    }
}

运行结果:

 五、守护线程

拿一个小案例来说明

public class 守护线程 {
    public static void main(String[] args){
        Thread t1=new Thread(){
            public void run(){
                for(int i=0;i<5;i++){
                    System.out.println("i will jump!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("噗通。。。。。");
            }
        };
        Thread thread2=new Thread(){
            public void run(){
                while(true){
                    System.out.println("you jump! i jump!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t1.start();
        thread2.start();
    }
}

在没有添加守护线程的条件下,thread2是不会受t1线程终止的影响而终止的

 但是当我们将thread2设置为守护线程后,t1停止thread2就会停止

public class 守护线程 {
    public static void main(String[] args){
        Thread t1=new Thread(){
            public void run(){
                for(int i=0;i<5;i++){
                    System.out.println("i will jump!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("噗通。。。。。");
            }
        };
        Thread thread2=new Thread(){
            public void run(){
                while(true){
                    System.out.println("you jump! i jump!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread2.setDaemon(true);
        t1.start();
        thread2.start();
    }
}

 其实java的public static void main(String[] args){} 就是一个守护线程

六、栅栏

当很多人约定好一个时间地点集合然后出发,我们需要保证当凑够五个人到了后才可以出发,这时我们可以设置一个栅栏(CyclicBarrier)

public class 栅栏CyclicBarrier {
    public static void main(String[] args){
        CyclicBarrier cb=new CyclicBarrier(5);
        for(int i=0;i<14;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Thread t=new Thread(){
                public void run(){
                    System.out.println("栅栏等待");
                    try {
                        cb.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.println("出发");
                }
            };
            t.start();
        }
    }
}

运行结果:

 因为一共就只有14个人,前十个人都可以正常出发,最后四个人因为凑不够五个人需要一直等待,线程处于阻塞状态

七、闭锁

因为线程是靠CPU分配时间来执行的,我们并不知道CPU会给线程分配到什么时间,但有时我们必须要求一个线程任务在某一时段执行,这时我们可以将所需线程加上一把锁(CountDownLatch)只有执行了所要求的线程数量后,才可以执行这个线程任务

public class 闭锁CountDownLatch {
    public static void main(String[] args){
        CountDownLatch cdl=new CountDownLatch(3);
        Thread t1=new Thread(){
            public void run(){
                System.out.println("准备发射。。。。。");
                cdl.countDown();
            }

        };
        Thread t2=new Thread(){
            public void run(){
                System.out.println("检查冷却装置。。。。。");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("冷却装置检查完毕");
                cdl.countDown();
            }
        };
        Thread t3=new Thread(){
            public void run(){
                System.out.println("检查氧气装置。。。。。");
                try {
                    Thread.sleep(20000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("氧气装置检查完毕");
                cdl.countDown();
            }
        };
        Thread thread=new Thread(){
            public void run(){
                try {
                    cdl.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("点火发射");
            }
        };
        t1.start();
        t2.start();
        t3.start();
        thread.start();
    }
}

我们将锁加在了点火发射的线程任务上

运行结果:

 八、睡眠阻断

可以通过interrupt()方法,将处于睡眠状态的线程阻断其睡眠,令其继续执行

public class 睡眠阻断 {
    public static void main(String[] args){
        Thread thread1=new Thread(){
            public void run(){
                try {
                    Thread.sleep(2000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("睡美人说 哎呀妈呀 破了相了");
            }
        };
        Thread thread2=new Thread(){
            public void run(){
                for(int i=0;i<10;i++){
                    System.out.println("八十");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("墙破了");
                thread1.interrupt();
            }
        };
        thread1.start();
        thread2.start();
    }
}

九、volatile 共享变量

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰后,那么就具备了两层语义:

1、保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的

2、禁止进行指令重排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值