Java多线程的一些知识

Java多线程

创建线程有四种方法,让我们来一一见识一下吧!

创建多线程方法1

1.自己写一个类继承Thread类

2…重写父类的run()方法

3.创建自己写的类的对象

4.利用对象名.start()方法来创建线程

class MyFrame extends Thread{     //1.自己写一个类继承Thread类
    public void run(){            //2.重写父类的run()方法
        for(int i=0;i<100;i++){
            if(i%2==0){
                System.out.println(i);
            }
        }
    }
}

public class Test5 {
    public static void main(String[] args) {
        MyFrame s=new MyFrame();                  //主线程
        s.start();     //另一个线程
        for(int i=0;i<100;i++){
            if(i%2==0){
                System.out.println(i+"****************");   //输出结果会乱序!
            }
        }
    }
}

Thread类的方法

/*
*  Thread类的方法
*  1.strat()方法:启动当前线程,调用Thread类重写的run()方法
*  2.run()方法:将创建的线程要执行的操作声明在此方法中
*  3.currentThread():静态代码,返回执行当前代码的线程
*  4.getName():返回当前线程的名字
*  5.setName():设置当前线程的名字
*  6.yield(): 释放当前cpu的执行权(但是有可能又被当前线程占用,只是说其他线程机会要大一些,但不绝对!)
*  7.join(): 在线程A中调用线程B的join()方法,则线程A进入阻塞状态,当线程B执行完以后再执行A!
*  8.stop(): 已过时,当执行此方法,强制结束当前线程(一般不建议使用!)
*  9.sleep(long milltime): 让当线程休息,单位为毫秒!
*  10.isAlive(): 判断线程是否还存活!
*
*  线程的优先级:
*  MAX_PRIORITY: 10
*  MIN_PRIORITY: 1
*  NORM_PRIORITY: 5(一般默认为5)
*  getPriority():获得线程的优先级!
*  setPriority():设置线程的优先级!
*/

class MyFrame1 extends Thread{
    public void run(){
        for(int i=0;i<100;i++){
            if(i%2 == 0){
                try{sleep(10000);
                }     //因为sleep原函数会抛异常,所以用try catch语句
            catch (Exception e){
                e.printStackTrace();
            }
                System.out.println(Thread.currentThread().getName()+":"+i);

            }
        }
    }
}

public class Test7 {
    public static void main(String[] args) {
        MyFrame s=new MyFrame();                  //主线程
        s.setName("线程一");       //修改线程名
        s.start();     //另一个线程  只能调用一次!
        s.currentThread().setName("主线程");    //修改主线程名

        try{s.join();}
        catch (Exception e){
            e.printStackTrace();  //和sleep()的用法一样!
        }
        for(int i=0;i<100;i++){
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i+"****************");   //输出结果会乱序!
            }
        }
        System.out.println(s.isAlive());
    }
}

创建线程的第二种方法

/*
* 创建线程的第二种方法!:实现Runnable接口
*  1.创建一个实现了Runnable接口的类
*  2.类去实现Runnable接口中的run()方法
*  3.创建实现类的对象
*  4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
*  5.通过Thread类的对象调用start()方法
*/


class MyRunnable implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            if(i%2 == 0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}
public class Test8 {
    public static void main(String[] args) {
        MyRunnable s = new MyRunnable();
        Thread th1 = new Thread(s);
        th1.setName("线程一");
        th1.start();
    }

}

创建线程的第二种方法的实例

//实现三个窗口卖票
class MyRunnable implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while(true){
        if(ticket > 0){
            System.out.println(Thread.currentThread().getName()+"卖票 票号:"+ticket);
            ticket--;
        }
        else{
            break;
        }
        }
    }
}
public class Test8 {
    public static void main(String[] args) {
        MyRunnable s = new MyRunnable();
        Thread th1 = new Thread(s);
        Thread th2 = new Thread(s);
        Thread th3 = new Thread(s);
        th1.setName("窗口一");
        th2.setName("窗口二");
        th3.setName("窗口三");

        th1.start();
        th2.start();
        th3.start();
    }
}

上面的输出结果你会发现是乱序的,原因就是发生了线程的安全问题!

线程的安全问题

/*
*   1.问题:上个例子会出现错票和重票的问题! -->出现了线程的安全问题
*   2.问题出现的原因:当某个线程操作的过程中,尚未操作完成,其他的线程也进入来操作!
*   3.如何解决:当某一个线程操作的过程中,我们给它加一把锁,当这个线程操作完成过后,其他线程才能进入操作!
*     注:即使当前线程被阻塞,其他的线程也不能够进入!
*   4.在Java中,利用同步机制来解决这个问题!
*   方法一:同步代码块
*   synchronizedh(同步监视器){
*   //需要被同步的代码(即对共享资源的操作)
*   }
*    注:1.操作共享数据的代码,即需要被同步的代码。
*       2.共享数据,多个线程共同操作的变量。比如:ticket
*       3.同步监视器,俗称锁,任何一个类的对象都可以充当锁。
*       4. 要求:多个线程必须共用同一把锁!
*/
class MyRunnable1 implements Runnable{
    private int ticket = 100;
    Object obj = new Object();
    @Override
    public void run() {
            while (true) {
                synchronized (obj) {
                    if (ticket > 0) {
                        try{
                            Thread.sleep(1000);   //静态方法

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
                        ticket--;
                    } else {
                        break;
                    }
                }
            }
    }
}
public class Test9 {
    public static void main(String[] args) {
        MyRunnable1 s = new MyRunnable1();
        Thread th1 = new Thread(s);
        Thread th2 = new Thread(s);
        Thread th3 = new Thread(s);
        th1.setName("窗口一");
        th2.setName("窗口二");
        th3.setName("窗口三");

        th1.start();
        th2.start();
        th3.start();
    }
}

使用第一种方法的实例

class MyFrame2 extends Thread{
    private static int ticket = 100;
    private static Object obj = new Object();  //设置为静态对象
    @Override
    public void run() {
        while (true) {
            synchronized (obj) {  
                if (ticket > 0) {
                    try{
                        Thread.sleep(10);

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "卖票 票号:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
        }
}
public class Test10 {
    public static void main(String[] args) {
        MyFrame2 x1 = new MyFrame2();
        MyFrame2 x2 = new MyFrame2();
        MyFrame2 x3 = new MyFrame2();
        x1.setName("窗口1");
        x2.setName("窗口2");
        x3.setName("窗口3");
        x2.start();
        x1.start();
        x3.start();
    }
}

同步方法

1.用接口实现
class MyRunnable3 implements Runnable{
    private int ticket = 100;
    Object obj = new Object();
    @Override
    public  void run() {
        while (true) {
              show();
        }
    }
    public synchronized void show(){    //同步方法
        if (ticket > 0) {
            try {
                Thread.sleep(10);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
            ticket--;
        }
    }
}
public class Test11 {
    public static void main(String[] args) {
        MyRunnable1 s = new MyRunnable1();
        Thread th1 = new Thread(s);
        Thread th2 = new Thread(s);
        Thread th3 = new Thread(s);
        th1.setName("窗口一");
        th2.setName("窗口二");
        th3.setName("窗口三");

        th1.start();
        th2.start();
        th3.start();
    }
}
2.用继承实现
class MyFrame4 extends Thread{
    private static int ticket = 100;
    private static Object obj = new Object();
    @Override
    public void run() {
        while (true) {
            show();
        }
    }
    public static synchronized void show(){  //监视器为 MyFrame4.class
        if (ticket > 0) {
            try{
                Thread.sleep(10);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
            ticket--;
        }

    }
}
public class Test12 {
    public static void main(String[] args) {
        MyFrame4 x1 = new MyFrame4();
        MyFrame4 x2 = new MyFrame4();
        MyFrame4 x3 = new MyFrame4();
        x1.setName("窗口1");
        x2.setName("窗口2");
        x3.setName("窗口3");
        x2.start();
        x1.start();
        x3.start();
    }
}

线程的死锁

/*
*   线程的死锁的问题
*   1.死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,
*   都在等待对方放弃自己需要的同步资源,就形成了线程死锁!
*
*   2.说明:
*   出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于堵塞状态,无法继续
*
*   举一个例子:人吃饭要两双筷子,现在桌子上有两双筷子,有两个人,让他们去抢,结果肯定有三种情况,一人一支筷子
*   就相当于死锁,都在等对方放弃自己的资源!
*/

public class Test13 {
    public static void main(String[] args) {
        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();

        new Thread(){
            @Override
            public void run() {
                synchronized (s1){
                    s1.append("1");
                    s2.append("a");
                    try {
                        sleep(100);   //增加死锁的概率
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s2){
                    s1.append("2");
                    s2.append("b");
                    System.out.println(s1);
                    System.out.println(s2);
                }
                }
            }
        }.start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (s2){
                    s1.append("3");
                    s2.append("c");
                    try {
                        Thread.sleep(100);   //增加死锁的概率
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s1){
                        s1.append("4");
                        s2.append("d");
                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();
    }
}

线程安全问题解决方案三:Lock锁

import java.util.concurrent.locks.ReentrantLock;
/*
*   解决线程安全问题的方式三:Lock锁
*
*/
class MyRunnable5 implements Runnable{
    private int ticket = 100;
    private ReentrantLock lock1= new ReentrantLock(); //1.定义一个ReentrantLock类的对象! 
    @Override
    public  void run() {
        while (true) {
            lock1.lock();   //2.使用lock()方法锁住
            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
                ticket--;
                lock1.unlock();   //3.使用unlock()方法解锁
        }
    }
    }
}
public class Test14 {
    public static void main(String[] args) {
        MyRunnable1 s = new MyRunnable1();
        Thread th1 = new Thread(s);
        Thread th2 = new Thread(s);
        Thread th3 = new Thread(s);
        th1.setName("窗口一");
        th2.setName("窗口二");
        th3.setName("窗口三");

        th1.start();
        th2.start();
        th3.start();
    }
}

线程通信

  • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器

  • notify():一旦执行此方法,就会唤醒被wait()的一个线程,如果有多个线程被wait(),就会唤醒优先级高的线程

  • notifyAll():一旦被执行,就会唤醒所以被wait的线程

  • 说明:

  • 1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中

  • 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器

  • 否则会出现异常

  • 3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中的

/* 1.线程通信
*   wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
*   notify():一旦执行此方法,就会唤醒被wait()的一个线程,如果有多个线程被wait(),就会唤醒优先级高的线程
*   notifyAll():一旦被执行,就会唤醒所以被wait的线程
*
*   说明:
*   1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中
*   2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器
*   否则会出现异常
*   3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中的
*/
class MyThread6 implements Runnable{
    int number = 0;
    @Override
    public void run() {
        while(true){
            synchronized (this) {
                notify();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(number <= 100){
                    System.out.println(Thread.currentThread().getName()+": "+number);
                    number++;
                }
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
        }
    }
}
public class Test16 {
    public static void main(String[] args) {
        MyThread6 s = new MyThread6();
        Thread th1 = new Thread(s);
        Thread th2 = new Thread(s);
        th1.setName("线程一");
        th2.setName("线程二");
        th1.start();
        th2.start();
    }
}

线程通信的一个例题

现有店员 顾客 生产者,当生产者生产到20,店员就会告诉他停一下再生产,当店里没有东西时,店员就会告诉顾客让他等一下再购买!

class Clerk{
    int produceNumber = 0;

  public synchronized void Reduce() {
      if (produceNumber > 0) {
          produceNumber--;
          System.out.println(Thread.currentThread().getName() + "开始消费,产品还剩" + produceNumber);
          notify();
      }
      if(produceNumber == 0){
          try {
              wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
  }
  public synchronized void Add(){
      if (produceNumber < 20){
      produceNumber++;
      System.out.println(Thread.currentThread().getName()+"开始生产,产品有"+produceNumber);
          notify();
  }
      if(produceNumber == 20){
          try {
              wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
  }
}
class Customer extends Thread{
  private Clerk cle;
  public Customer(Clerk cle){
      this.cle=cle;
  }
    @Override
    public void run() {
      while (true) {
          try {
              sleep(10);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          cle.Reduce();

      }
    }
}
class Producer extends Thread{
   private Clerk cle;
    public Producer(Clerk cle){
        this.cle=cle;
    }

    @Override
    public void run() {
        while (true) {
            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            cle.Add();
        }
    }
}
public class Test17{
    public static void main(String[] args) {
      Clerk cle = new Clerk();
      Customer cus = new Customer(cle);
      Producer pro = new Producer(cle);
      cus.setName("顾客");
      pro.setName("生产者");
      cus.start();
      pro.start();
    }
}

创建线程方法三

/*  创建线程的方法三:
*   1.创建一个类实现Callable接口
*   2.创建一个实现了Callable接口的类的对象
*   3.将该对象作为参数传递到FutureTask类的构造器,并构造对象!
*   4.将FutureTask类的对象作为参数传递到Thread类的构造器!
*   5.调用Thread类对象.start()方法
*   6.如果需要实现了Callable接口类call方法的返回值,则调用FutureTask类的对象.get()
*
*/
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class NumThread implements Callable{
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 0; i <100 ; i++) {
            if (i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

public class Test18 {
    public static void main(String[] args) {
        NumThread numThread = new NumThread();
        FutureTask futureTask = new FutureTask(numThread);
        new Thread(futureTask).start();
        try {
            Object sun = futureTask.get();
            System.out.println("总和为:"+sun);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

创建线程方法四

/*  利用线程池来创建线程
*   
*/
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class NumberThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i%2==0){
                System.out.println(i);
            }
        }
    }
}

public class Test19 {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10); //设置线程池的大小
        service.execute(new NumberThread());   //运行run方法
        service.shutdown();  //关闭线程池
    }
}

如果本篇文章对您有些帮助的话,点个赞,激励一下博主!嘻嘻!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小猪~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值