Day 14(线程的创建和使用)

目录

一、多线程的创建

二、小练习

三、Thread常用方法

四、线程的优先级

五、同步机制 

六、进程通信


一、多线程的创建

     方式一:

(Thread.currentThread().getName() :返回当前线程的名字)

/**

        1、创建一个继承于Thread的子类

        2、重写Thread类的run()--- 将此线程执行的操作写在该方法中

        3、创建Thread类的子类对象

        4、通过此对象调用start()

*/


public class ThreadTest {
    public static void main(String[] args) {
        //3、创建Thread类的子类的对象
        MyTread myThread = new MyTread();
        //4、通过此对象调用start()  作用:启动当前线程;调用当前线程的run()
        //不可以让已经start()过的再次start()--要重新创建对象调用start()方法
        myThread.start();
        //main()线程中执行
//        for (int i=0;i<=100;i++){
//            if (i%2==0){
//                //Thread.currentThread().getName() :返回当前线程的名字
//                System.out.println(Thread.currentThread().getName() + ": yeah");
//            }
//        }
    }
}
 // 1、创建一个继承于Thread的子类
class MyTread extends Thread{
//2、重写Thread类的run()
        @Override
        public void run() {
//打印100以内的偶数
            for (int i=0;i<=100;i++){
                if (i%2==0){
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }
    }

        方式二:

    /*
    方式二:实现Runnable接口
        1) 定义子类,实现Runnable接口。
        2) 子类中重写Runnable接口中的run方法。
        3) 通过Thread类含参构造器创建线程对象。
        4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
        5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
    */

public class ThreadTest2 {
    public static void main(String[] args) {
        //3) 通过Thread类含参构造器创建线程对象
        MThread mThread1 = new MThread();
        //4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中
        Thread t = new Thread(mThread1);  //此处创建Thread的对象,调用Thread线程的有参构造器,将mThread1赋给构造器中的target,然后调用target的run()方法
        //5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法
        t.start();

        //此时实现类mThread1共享,只需要重新将子类对象作为实际参数传递给Thread类的构造器中
        Thread t1 = new Thread(mThread1);
        t1.start();
    }
}


//1) 定义子类,实现Runnable接口
class MThread implements Runnable{
//2) 子类中重写Runnable接口中的run方法
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
        }
    }
}

        方式三:实现Callable接口

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//创建线程方式三:实现Callable接口
public class CallableTest {
    public static void main(String[] args) {
        //3、创建Callable接口实现类的对象
        newThread newThread = new newThread();
        //4、借助FutureTask类,创建FutureTask类的对象,并将实现类的对象传入FutureTask的构造器中
        FutureTask futureTask = new FutureTask(newThread);

        //5、将FutureTask类的对象传入Thread构造器中,创建Thread类的对象, 并启动线程
        Thread thread = new Thread(futureTask);
        thread.start();

        //6、调用FutureTask类的get()方法--获取call()方法的返回结果

        try {
            Object sum = futureTask.get();
            System.out.println("the total is : " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

//1、实现Callable类
class newThread implements Callable{
    //2、重写call()方法  将需要执行的操作声明在call()方法中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i%2==0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

        方式四:使用线程池创建多线程 (...)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {
    public static void main(String[] args) {
        //1 提供指定线程数得线程池
        ExecutorService service = Executors.newFixedThreadPool(5);
        //2 执行执行线程操作  需要提供实现Runnable接口或Callable接口实现类得对象
        service.execute(new myPool1());  //适用于runnable接口
        service.execute(new myPool2());
        //service.submit(Callable callable);   适用于Callable接口
        //3 关闭线程池
        service.shutdown();
    }
}

class myPool1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 40; i++) {
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

二、小练习

        创建两个分线程,分别打印100以内的偶数和奇数 

public class ThreadTest {
    public static void main(String[] args) {
        //创建创建Thread类的子类的对象
        MyTread myThread = new MyTread();
        MyThread1 myThread1 = new MyThread1();
        //通过此对象调用start()  作用:启动当前线程;调用当前线程的run()
        //不可以让已经start()过的再次start()--要重新创建对象调用start()方法
        myThread.start();
        myThread1.start();
    }
}
    /*
    方式一:继承于Thread类的子类
            1、创建一个继承于Thread的子类
            2、重写Thread类的run()  --将此线程执行的操作写在该方法中
            3、创建Thread类的子类的对象
            4、通过此对象调用start()
     */
class MyTread extends Thread{
        @Override
        public void run() {
            for (int i=0;i<=100;i++){
                if (i%2==0){
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }
    }

class MyThread1 extends Thread{
        @Override
        public void run() {
            for (int i=0;i<=100;i++){
                if (i%2==1){
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }
}

/*
       创建Thread类的匿名子类的方式
       new className(){
            @Override
            public void run() {
                //重写的run()方法
            }
        }.start();
*/
        new MyTread(){
            @Override
            public void run() {
                for (int i=0;i<=100;i++){
                    if (i%2==0){
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();

三、Thread常用方法

/**
 * 1、setName() 设置当前线程名称
 * 2、getName() 获取当前线程名称
 * 3、currentThread() 静态方法 返回执行当前代码的线程
 * 4、yield()  释放当前cpu的执行权
 * 5、join()  在线程a中调用线程b的join(),此时线程a进入阻塞状态,直到线程b执行完毕,才会结束线程a的阻塞状态,开始执行线程a
 * 6、sleep(time) 让指定线程睡眠,指定线程此时属于阻塞状态
 * 7、isAlive()  判断当前线程是否存活  返回true or false
 */
        Thread1 thread1 = new Thread1();
        //设置thread1的线程名
        thread1.setName("线程一");
        thread1.start();
        for (int i = 0; i < 50; i++) {
            //当main线程中的i==25时,main()进入阻塞状态,开始执行thread1线程
            if (i == 25){
                try {
                    //在main线程中调用thread1线程的join()方法
                    thread1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
   

四、线程的优先级

     /**
     * 线程的优先级
     *      1、优先级别
     *          MAX_PRIORITY:10
     *          MIN _PRIORITY:1
     *          NORM_PRIORITY:5  默认优先级
     *      2、获取和设置优先级
     *          setPriority()
     *          getPriority()
     */
         //获取和设置优先级
        System.out.println(thread1.getPriority());  //5
        thread1.setPriority(Thread.MAX_PRIORITY);

五、同步机制 

        1、通过同步机制来解决线程安全问题

                (1)同步代码块

/**
 * 同步机制:
 *      方式一:同步代码块
 *          synchronized (对象){
 *              // 需要被同步的代码;
 *          }
 *          (1)操作共享数据的代码,即为需要被同步的代码
 *          (2)共享数据:多个线程共同操作的变量(如ticket)
 *          (3)同步监视器(锁),任何一个类的对象都可以(要求:多个线程必须公用同一把锁)
 */
//同步代码块解决runnable线程安全问题

public class SoldTicketTest1 {
    public static void main(String[] args) {
        //只创建了一个SoldTicket1对象,类中属性共享
        SoldTicket1 soldTicket1 = new SoldTicket1();
        Thread thread1 = new Thread(soldTicket1);
        Thread thread2 = new Thread(soldTicket1);
        Thread thread3 = new Thread(soldTicket1);
        thread1.setName("window 1");
        thread2.setName("window 2");
        thread3.setName("window 3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class SoldTicket1 implements Runnable {
        private int ticket = 100;
        //公用同一把锁
//        Object obj = new Object();
        @Override
        public void run() {
            while (true) {
                //同步代码块:obj是锁
//                synchronized(obj) {
                  synchronized (this){ //this:唯一的SoldTicket1的对象即soldTicket1
                    //操作共享变量(ticket)的代码块
                    if (ticket > 0) {

                    //增大线程不安全的概率
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
                        ticket--;
                    } else
                        break;
                }
            }
        }
}
//同步代码块解决继承中的线程安全问题

public class SoldTicketTest2 {
    public static void main(String[] args) {
        //声明了三个对象
        SoldTicket2 s1 = new SoldTicket2();
        SoldTicket2 s2 = new SoldTicket2();
        SoldTicket2 s3 = new SoldTicket2();
        //修改线程名称
        s1.setName("window 1 ");
        s2.setName("window 2 ");
        s3.setName("window 3 ");
        //启动线程
        s1.start();
        s2.start();
        s3.start();
    }
}
class SoldTicket2 extends Thread{
    //设置static共享
    private static int ticket = 100;
    //公用同一把锁(继承中必须设置为static才能共享)
    private static Object obj = new Object();
    @Override
    public void run() {
        while (true) {
            //同步代码块:obj是锁
            synchronized(obj) {
            //synchronized (SoldTicket2.class){  //SoldTicket2.class:当前类,只会加载一次,可行
            //synchronized(this) {  在使用继承的方式创建线程:不能直接使用this:代表s1 s2 s3  不是同一把锁

                //操作共享变量(ticket)的代码块
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
                    ticket--;
                } else
                    break;
            }
        }
    }
}

                (2)、同步方法

//使用synchronized方法解决runnable线程安全问题
public class SoldTicketTest3 {
    public static void main(String[] args) {
        SoldTicket3 soldTicket = new SoldTicket3();
        Thread thread1 = new Thread(soldTicket);
        Thread thread2 = new Thread(soldTicket);
        Thread thread3 = new Thread(soldTicket);
        thread1.setName("window 1");
        thread2.setName("window 2");
        thread3.setName("window 3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class SoldTicket3 implements Runnable{  //此时锁是this
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            //调用类中的synchronized方法
            show();
        }
    }
    //将操作共享数据的代码封装在一个synchronized方法中
    private synchronized void show(){
        if (ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
            ticket--;
        }
    }
}
//使用synchronized方法解决继承中的线程安全问题
public class SoldTicketTest4 {
    public static void main(String[] args) {
        //声明了三个对象
        SoldTicket4 s1 = new SoldTicket4();
        SoldTicket4 s2 = new SoldTicket4();
        SoldTicket4 s3 = new SoldTicket4();
        //修改线程名称
        s1.setName("window 1 ");
        s2.setName("window 2 ");
        s3.setName("window 3 ");
        //启动线程
        s1.start();
        s2.start();
        s3.start();
    }
}
class SoldTicket4 extends Thread{
    //设置static共享
    private static int ticket = 100;
    //公用同一把锁(继承中必须设置为static才能共享)
    private static Object obj = new Object();
    @Override
    public void run() {
        while (true) {
                show();
            }
        }
        //将synchronized方法声明为static 才是同一把锁(SoldTicket4.class)
        private static synchronized void show(){
            if (ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
                ticket--;
            }
        }
}

        2、Lock

import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用Lock解决Runnable中线程安全问题
 * class A{
 *     private final ReentrantLock lock = new ReenTrantLock();
 *     public void m(){
 *         lock.lock();
 *         try{
 *             //保证线程安全的代码; }
 *         finally{
 *         lock.unlock();
 *        } } }
 */

public class LockTest {
    public static void main(String[] args) {
        SoldTicket5 soldTicket5 = new SoldTicket5();
        Thread t1 = new Thread(soldTicket5);
        Thread t2 = new Thread(soldTicket5);
        Thread t3 = new Thread(soldTicket5);
        t1.setName("window 1");
        t2.setName("window 2");
        t3.setName("window 3");
        t1.start();
        t2.start();
        t3.start();
    }
}

class SoldTicket5 implements Runnable {
    private int ticket = 100;
    //通过显式定义同步锁对象来实现同步,同步锁使用Lock对象充当
    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                //显示加锁
                lock.lock();
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": " + ticket);
                    ticket--;
                }
            } finally {
                //解锁
                lock.unlock();
            }
        }
    }
}

六、进程通信

/**
 * 线程通信:
 *
 * 线程通信方法:(1、以下三个方法必须使用在同步代码块或同步方法中  2、三个方法的调用者必须是同步代码块或同步方法中的同步监视器)
 *      wait(): A线程执行此方法,进入阻塞状态,释放同步监视器,则B线程可以拿到此监视器
 *      notify(): B线程执行此方法,就会唤醒一个被wait()的线程,如果有多个被wait()线程,则唤醒优先级较高的那一个线程
 *      notifyAll(): 执行此方法,就会唤醒所有被wait()的线程
 */

//使用两个线程交替打印 1-100


public class ThreadCommunication {
    public static void main(String[] args) {
        Communication c = new Communication();
        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        t1.setName("Thread 1");
        t2.setName("Thread 2");
        t1.start();
        t2.start();
    }
}

//实现Runnable
class Communication implements Runnable{
    private int number = 1;
//    Object obj = new Object();

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public void run() {
        while (true){
            //实现类 采用synchronized方法,锁可以直接用this(指Communication的对象)
            synchronized (this) {
                //调用notify()的线程释放阻塞进程  比如线程1进来--打印--线程1阻塞--线程2进来--释放线程1--打印--线程2阻塞--线程1进来--释放线程2--打印...
                notify();  //其实是this.notify();
                //obj.notify();
                //延迟
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (number <= 100){
                    System.out.println(Thread.currentThread().getName() + ": " + number);
                    number++;
                }else{
                    break;
                }
                //调用wait()的线程进入阻塞状态
                try {
                    wait();   //其实是this.wait();
               // obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值