一.创建线程的两种方式

1.继承Thread

class MyThread extends Thread{

    private static int ticket = 10;
    private String name;
    public MyThread(String name){
        this.name =name;
    }

    public void run(){
        while(this.ticket>0){
            System.out.println(this.name+"卖票---->"+(this.ticket--));
        }
    }
}

2.实现Runnable接口

class MyThread implements Runnable{  
    private int ticket =10;  
    private String name;  
    public void run(){
        while(this.ticket>0){
            System.out.println(this.name+"卖票---->"+(this.ticket--));
        }
    }
}

二.线程的5种状态

Java多线程机制synchronized java的多线程机制_多线程


1.新生状态(创建状态)。在生成线程对象,但是没有调用对象的start()方法时,该线程处于创建状态

2.就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,此时线程具有CPU的执行资格,但是没有CPU的执行权。

3.运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,开始运行run函数当中的代码,此时线程就进入运行状态,处于运行状态的线程既有CPU的执行资格,又有CPU的执行权。

4.阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。此时线程既没有CPU的执行资格,也没有CPU的执行权。

5.死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪转态。

  • sleep()与wait()的区别?
    如果当前线程进入了同步锁,调用sleep()方法并不会释放锁,其他被同步锁挡住了的线程也无法得到执行,在sleep()指定的时间过后,线程会自动回到就绪状态等待CPU的执行;而wait()方法会释放同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只用其他线程调用了notify()或notifyAll()方法,线程才会回到就绪状态。但是notify()方法并不释放同步锁,只是告诉调用过wait()方法的线程去参与同步锁的竞争,但不是马上得到锁,因为锁在别人手里,别人还没释放。

三.线程的同步

  • 同步与异步有何不同,在什么情况下使用它们?
    如果数据在多个线程之间共享并且操作共享数据的代码不止一条时,就需要对共享数据进行同步处理,即某一个线程在操作共享数据时,其他线程无法操作,只到该线程释放共享数据。当应用程序调用一个需要花费很长时间来执行的方法,并且不需要等待返回结果时,就采取异步操作,例如:下载资源。
  • 同步的好处和弊端?
    好处:解决了线程的安全性问题
    弊端:降低了效率,因为同步外的线程都要判断同步锁

1.同步代码块

思路:将操作共享数据的多条代码封装起来

package com.ghs.sort;

public class Demo{
    public static void main(String[] args){
        Ticket t = new Ticket();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class Ticket implements Runnable{
    int num=100;    //所有的线程共用一个num对象
    Object obj = new Object();
    public void run(){
        while(true){
            synchronized(obj){
                if(num>0){
                    System.out.println(Thread.currentThread().getName()+"......sale......"+num--);
                }
            }
        }
    }
}

同步锁就相当于一个标志位,初始值为1,有线程进去了,值就变为0,只有当同步锁为1的时候,其他线程才能进去。

2.同步函数

public class Demo {
    public static void main(String[] args) {
        BankRun br = new BankRun();
        Thread t1 = new Thread(br);
        Thread t2 = new Thread(br);
        t1.start();
        t2.start();
    }
}

class BankRun implements Runnable {
    Bank b = new Bank();
    public void run() {
        b.add(100);
    }
}

class Bank {
    private int sum;
    //模拟存钱的过程
    public synchronized void add(int num) { //此处存在安全问题,采用同步函数来解决
        sum = sum + num;
        System.out.println(Thread.currentThread() + "......Total=" + sum);
    }
}

注意:
1. 同步函数的锁是this
2. 静态同步函数的锁是Class对象而不是this,因为静态函数没有所属的对象

当一个线程进入一个对象的synchronized方法后,其他线程是否可以进入此对象的其他方法?
1. 其他方法前如果不是synchronized方法,则能进入。
2. 如果这个方法内部调用了wait,则能进入其他的synchronized方法。
3. 其他方法如果都加了synchronized,并且内部没有调用wait,则不能进入。
3. 如果其他方法是static,它的同步锁是当前类的字节码,与非静态方法不能同步,所以能进入。