First, sharing and collaboration between the thread and the thread base

Thread common method

method Explanation
static int activeCount() Returns the current estimate of the number of threads thread thread group and its subgroups activities.
void start() The thread begins execution; Java Virtual Machine calls the run method of this thread.
static Thread currentThread() Get the current thread of execution reference
long getId() Get thread id
String getName() Get Thread name
void setName(String name) Change the name of the thread.
int getPriority() Get Thread priority value
int setPriority(int priority) Change the priority of the thread.
Thread.State getState() Get Thread state
void interrupt() Interrupt this thread
boolean isInterrupted() Check whether the thread is interrupted.
static boolean interrupted() Tests whether the current thread has been interrupted, calling this method will restore the interrupt flag to false.
static void yield() Presented to the scheduler, the current thread is willing to give up the current thread processor.
void run() This method is called runtime execution thread
void sleep(long miliseconds) The currently executing thread to sleep (temporarily cease execution) for a specified number of milliseconds.
void join() Waiting thread death.
void join(long miliseconds) The specified number of milliseconds to wait for the thread to die.
boolean isAlive() Tests if this thread is active.
void suspend() To suspend the thread (deprecated).
void resume() For recovering suspended thread (deprecated).
void stop() To stop the thread (deprecated).
boolean isDaemon() Tests if this thread is a daemon thread.
void setDaemon(boolean b) The thread is marked as a daemon thread, set before the start method is called.

Start a thread of four ways

Inheritance Thread

class UseThread extends Thread {
    @Override
    public void run() {
        System.out.println("UseThread object run ...");
    }
    
    public static void main(String[] args) {
        UseThread useThread = new UseThread();
        useThread.start();
    }
}

Implement Runnable

class UseRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("UseRunnable object run ...");
    }
    public static void main(String[] args) {
        UseRunnable useRunnable = new UseRunnable();
        Thread thread = new Thread(useRunnable);
        thread.start();
    }
}

Implement Callable

class UseCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("UseCallable object call ...");
        return "call result";
    }

    public static void main(String[] args) {
        UseCallable callable = new UseCallable();
        FutureTask task = new FutureTask(callable);
        Thread thread = new Thread(task);
        thread.start();
        try {
            System.out.println("线程运行返回:" + task.get());
        } catch (InterruptedException | ExecutionException e) {
            task.cancel(true);//取消计算
            e.printStackTrace();
        }
    }
}

Using Executors

class NewThread {
    public static void main(String[] args) {
        Thread t = Executors.defaultThreadFactory().newThread(() -> System.out.println("使用Executors创建线程..."));
        t.start();
    }
}

Realization of the benefits of using Runnable

  • Avoiding the limitations of single inheritance, a class can implement multiple interfaces
  • Suitable for resource sharing

In order to sell tickets, for example, the use of inheritance Thread:

class Ticket {
    private int ticketNum;

    public Ticket(int ticketNum) {
        this.ticketNum = ticketNum;
    }

    public void sell() {
        while (true) {
            synchronized (this) {
                if (ticketNum <= 0) break;
                ticketNum--;
                System.out.println(Thread.currentThread().getName() + "卖出一张票,还剩[" + ticketNum + "]张票");
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class TicketThread extends Thread {
    private Ticket ticket;

    public TicketThread(Ticket ticket, String threadName) {
        super(threadName);
        this.ticket = ticket;
    }

    @Override
    public void run() {
        ticket.sell();
    }

    public static void main(String[] args) {
        //3个线程卖10张票
        Ticket ticket = new Ticket(10);
        new TicketThread(ticket, "线程1").start();
        new TicketThread(ticket, "线程2").start();
        new TicketThread(ticket, "线程3").start();
    }
}

That implement Runnable implementation:

class TicketRunnable implements Runnable {
    private int ticketNum;

    public TicketRunnable(int ticketNum) {
        this.ticketNum = ticketNum;
    }

    @Override
    public void run() {

        while (true) {
            synchronized (this) {
                if (ticketNum <= 0) break;
                ticketNum--;
                System.out.println(Thread.currentThread().getName() + "卖出一张票,还剩[" + ticketNum + "]张票");
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        //3个线程卖10张票
        TicketRunnable ticket = new TicketRunnable(10);
        new Thread(ticket, "线程1").start();
        new Thread(ticket, "线程2").start();
        new Thread(ticket, "线程3").start();
    }
}

Safe stop the thread method

public class RunnableImpl implements Runnable {
    @Override
    public void run() {

        //当执行中断方法interrupt()后,线程并不会停止,而是会继续执行完,线程与线程之间是一种协作状态
//        while(true){
//            System.out.println("UseThread object run ...");
//        }

        //需要受到控制的话,使用isInterrupted()方法判断一下
//        while (!Thread.currentThread().isInterrupted()) {
//            System.out.println(Thread.currentThread().getName() + " is run ...");
//        }

        //使用interrupted()方法判断中断状态会将中断标识恢复成false
//        while (!Thread.currentThread().interrupted()) {
//            System.out.println(Thread.currentThread().getName() + " is run ...");
//        }

        while (!Thread.currentThread().isInterrupted()) {
            System.out.println(Thread.currentThread().getName() + " is run ...");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                //抛出InterruptedException异常后中断标识会恢复成false
                //如果抛异常后需要中断,需要在调用interrupt()方法进行中断操作
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(Thread.currentThread().getName() + " interrupt flag is:" + Thread.currentThread().isInterrupted());
    }

    public static void main(String[] args) throws InterruptedException {
        RunnableImpl runnable = new RunnableImpl();
        Thread t = new Thread(runnable);
        t.start();
        Thread.sleep(2000);
        t.interrupt();
    }
}

Stop the thread is determined by the thread itself, reference calls interrupt () method uses thread to thread just to say hello.
Thread stop, resume, suspend method is not recommended, stop method may lead to incorrect thread release resources, suspend method is easy to cause thread deadlock

Daemon thread

Daemon threads are threads together with the main thread of death, the contents of the try finally block will not necessarily be executed.

Daemon thread: In the thread calls start () method before calling thread void setDaemon (boolean on) method, set to ture, then call start () method, the thread is the guardian of the thread.

Examples

/**
 * @CalssName DaemonThreadDemo
 * @Description 守护进程
 * @since JDK 1.8
 */
public class DaemonThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("I use Lambda expression...");
                }
            } finally {
                System.out.println("finally code...");
            }
        });
        t.setDaemon(true);
        t.start();
        Thread.sleep(50);
    }
}

Thread priority

Set thread priority example

/**
 * @CalssName ThreadPriority
 * @Description 线程优先级
 * @since JDK 1.8
 */
public class ThreadPriority {
    public static void main(String[] args) {

        Runnable runnable = new Runnable() {
            int t1count = 0, t2count = 0;

            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    synchronized (this) {
                        String tName = Thread.currentThread().getName();
                        if ("线程1".equals(tName)) {
                            t1count++;
                            System.out.println(tName + " run... " + t1count + "次");
                        }
                        if ("线程2".equals(tName)) {
                            t2count++;
                            System.out.println(tName + " run... " + t2count + "次");
                        }

                    }
                }
            }
        };
        Thread t1 = new Thread(runnable, "线程1");
        Thread t2 = new Thread(runnable, "线程2");
        t1.setPriority(Thread.MAX_PRIORITY);//最大优先级10
        t2.setPriority(Thread.MIN_PRIORITY);//最小优先级1
        t1.start();
        t2.start();
    }
}

The following operating results

Thread priority according to different systems, different implementations of the runtime is not set higher, CPU will certainly take precedence

Built-synchronized lock

Object lock: locks the object is out of the new class of objects
Locks: Locks lock is Class object class, Java virtual machine to ensure that each class has only one Class object

Locks and run the sample object lock

public class SynchronizedDemo {
    //对象锁
    public synchronized void test1() {
        synchronized (this) {
            //这也是对象锁
            System.out.println("方法中使用对象锁...");
        }
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(600);
            } catch (InterruptedException ie) {
            }
        }
    }

    //类锁
    public synchronized static void test2() {
        synchronized (SynchronizedDemo.class) {
            //这个也是类锁
            System.out.println("方法中使用类锁...");
        }
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(250);
            } catch (InterruptedException ie) {
            }
        }
    }

    public static void main(String[] args) {
        final SynchronizedDemo myt2 = new SynchronizedDemo();
        Thread test1 = new Thread(new Runnable() {
            public void run() {
                myt2.test1();
            }
        }, "test1");
        Thread test2 = new Thread(new Runnable() {
            public void run() {
                SynchronizedDemo.test2();
            }
        }, "test2");
        test1.start();
        test2.start();
    }
}

operation result

方法中使用对象锁...
test1 : 4
方法中使用类锁...
test2 : 4
test2 : 3
test2 : 2
test1 : 3
test2 : 1
test2 : 0
test1 : 2
test1 : 1
test1 : 0

The use of volatile

volatile is not thread safe, it can ensure the visibility of data, we can not guarantee the atomicity of data.
volatile under applicable only to the case of multiple threads to read a thread to write the use of its concurrent high efficiency.
Example of use:

public class VolatileDemo {
    private volatile int score;

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;

        //this.score = score + 10;//这种做法错误,因为volatile不能保证score的原子性
    }
}

Use of ThreadLocal

Multiple threads ThreadLocal variable, each thread are using a copy of this variable will not have access to this ThreadLocal variable value other threads.

method Method Description
public T get() The return value copy of the current ThreadLocal variable thread
protected T initialValue() The initial value of the ThreadLocal variable returns a copy of the current thread
public void remove() 删除当前线程中ThreadLocal变量副本的值
public void set(T value) 设置当前线程中ThreadLocal变量副本的值

下面是ThreadLocal变量和普通变量的区别示例

/**
 * @CalssName UseThreadLocal
 * @Description ThreadLocalDemo
 * @since JDK 1.8
 */
public class UseThreadLocal implements Runnable {
    private int count = 0;
    private ThreadLocal<Integer> threadLocal = new ThreadLocal() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        synchronized (this) {
            for (int i = 1; i <= 3; i++) {
                this.count += this.count + i;
                threadLocal.set(threadLocal.get() + i);
                System.out.println(threadName + " this.count:" + this.count);
                System.out.println(threadName + " threadLocal value:" + threadLocal.get());
            }
        }
    }

    public static void main(String[] args) {
        UseThreadLocal useThreadLocalRunnable = new UseThreadLocal();
        new Thread(useThreadLocalRunnable, "线程1").start();
        new Thread(useThreadLocalRunnable, "线程2").start();
        new Thread(useThreadLocalRunnable, "线程3").start();
    }
}

线程的等待与通知

wait():当前线程处于等待状态,并释放锁,既然要释放锁就必须先获得锁,而线程进入synchronized修饰的方法或者代码块中才能获得锁,所以wait()方法只能在synchronized修饰的方法或者代码块中才能使用。

notify():随机通知并唤醒一个使用wait()方法等待的线程。
notifyAll():通知并唤醒所有使用wait()方法等待的线程。
尽量使用notifyAll()方法,因为使用notify()有可能发生信号丢失的情况。

等待与通知的标准范式

  1. 等待线程获取到对象的锁,调用wait()方法,放弃锁,进入等待队列
  2. 通知线程获取到对象的锁,调用对象的notify()方法
  3. 等待线程接受到通知,从等待队列移到同步队列,进入阻塞状态
  4. 通知线程释放锁后,等待线程获取到锁继续执行

下面是使用wait()、notifyAll和synchronized内置锁做的简易链接池工具

/**
 * @CalssName DBPool
 * @Description 数据库链接池工具
 * @since JDK 1.8
 */
public class DBPool {

    private static LinkedList<Connection> pool = new LinkedList<>();
    private static String url = "jdbc:mysql://192.168.86.101:3306/mysql";
    private static String username = "root";
    private static String password = "my-pwd";

    /**
     * @return java.sql.Connection
     * @Title getConnection
     * @Description 从链接池中获取链接,如果没有链接了在指定有效时间内获取链接,不然返回null
     * @Param [mills] 没有链接时指定获取去时间
     * @Throws InterruptedException
     */
    public Connection getConnection(long mills) throws InterruptedException {
        synchronized (pool) {
            if (mills <= 0) {
                while (pool.isEmpty()) {
                    //链接被用光了,等待回收链接
                    pool.wait();
                }
                //有链接了
                return pool.removeFirst();
            } else {
                long overTime = System.currentTimeMillis() + mills;
                long remain = mills;
                while (pool.isEmpty() && remain > 0) {
                    //没链接了,等待指定时间
                    pool.wait(remain);
                    remain = overTime - System.currentTimeMillis();
                }
//                指定时间后还没有链接就返回null
                if (pool.isEmpty()) return null;
                return pool.removeFirst();
            }
        }
    }

    /**
     * @CalssName DBPool
     * @Description 释放链接
     * @since JDK 1.8
     */
    public void releaseConnection(Connection connection) {
        if (connection != null) {
            synchronized (pool) {
                pool.addLast(connection);
                //链接回收了,通知其他等待的线程使用
                pool.notifyAll();
            }
        }
    }

    /**
     * @CalssName DBPool
     * @Description 初始化链接池
     * @since JDK 1.8
     */
    public DBPool(int initSize) {
        if (initSize > 0) {
            try {
                Class.forName("com.mysql.jdbc.Driver");
                for (int i = 0; i < initSize; i++) {
                    Connection connection = DriverManager.getConnection(url, username, password);
                    pool.add(connection);
                }
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        new DBPool(10);
        System.out.println(pool.size());
    }
}

Join方法

如果线程A调用线程B的join()方法之后就必须等待线程B执行完,线程A才会执行

示例

/**
 * @CalssName ThreadUseJoin
 * @Description 使用join
 * @since JDK 1.8
 */
public class ThreadUseJoin {
    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ",i:" + i);
            }
        }, "t1");
        t1.start();

        Thread t2 = new Thread(() -> {
            try {
                t1.join();//等t1线程执行完销毁才开始执行
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + ",i:" + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2");
        t2.start();
    }
}

Yield方法

yield方法执行后并不会释放锁,而是放弃当前在CPU的运行权力,等待下一次CPU调度执行。

执行sleep和notify、notifyAll方法也不会释放锁,notify、notifyAll执行之后唤醒其他线性,但唤醒的以及其他线程仍然处于阻塞状态,直到当前synchronized修饰的代码执行完其他线程才会获取锁

Guess you like

Origin www.cnblogs.com/yhongyin/p/11117749.html