整理总结Java多线程程序编写的要点

线程状态图

线程共包括以下5种状态。

1. 新建状态(New)         : 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。

2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。

3. 运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。

4. 阻塞状态(Blocked)  : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

(01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。

(02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。

(03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5. 死亡状态(Dead)    : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

实现多线程的方式Thread和Runnable
Thread:继承thread类,实现run方法,在main函数中调用start方法启动线程

Runnable:接口,实现Runnable接口,作为参数传递给Thread的构造函数,在main中调用start方法

例子:

class task implements Runnable {

  private int ticket = 10;

  @Override
  public void run() {
    for (int i = 0; i < 20; i++) {
      if (this.ticket > 0) {
        System.out.println(Thread.currentThread().getName()
            + " sold ticket " + this.ticket--);
      }
    }
  }

};

public class RunnableTest {
  public static void main(String[]args){
    task mytask = new task();
    Thread t1 = new Thread(mytask);
    Thread t2 = new Thread(mytask);
    Thread t3 = new Thread(mytask);
    t1.start();
    t2.start();
    t3.start();
  }

}

//ThreadTest.java 源码
class MyThread extends Thread {
  private int ticket = 10;

  public void run() {
    for (int i = 0; i < 20; i++) {
      if (this.ticket > 0) {
        System.out.println(this.getName() + " 卖票:ticket"
            + this.ticket--);
      }
    }
  }
}

public class ThreadTest {
  public static void main(String[] args) {
    // 启动3个线程t1,t2,t3;每个线程各卖10张票!
    MyThread t1 = new MyThread();
    MyThread t2 = new MyThread();
    MyThread t3 = new MyThread();
    t1.start();
    t2.start();
    t3.start();
  }
};

Thread与Runnable的区别

Thread 是类,而Runnable是接口;Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。通常,建议通过“Runnable”实现多线程!

Thread的run与start

start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用。start()实际上是通过本地方法start0()启动线程的。而start0()会新运行一个线程,新线程会调用run()方法。

run()   : run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!run()就是直接调用Thread线程的Runnable成员的run()方法,并不会新建一个线程。

// Demo.java 的源码
class MyThread extends Thread{
  public MyThread(String name) {
    super(name);
  }

  public void run(){
    System.out.println(Thread.currentThread().getName()+" is running");
  }
}; 

public class Demo {
  public static void main(String[] args) {
    Thread mythread=new MyThread("mythread");

    System.out.println(Thread.currentThread().getName()+" call mythread.run()");
    mythread.run();

    System.out.println(Thread.currentThread().getName()+" call mythread.start()");
    mythread.start();
  }
}

输出:

main call mythread.run()
main is running
main call mythread.start()
mythread is running

synchronized
在java中每个对象都有一个同步锁,当我们调用对象的synchronized方法就获取了对象锁,synchronized(obj)就获取了“obj这个对象”的同步锁.不同线程对同步锁的访问是互斥的.某时间点对象的同步锁只能被一个线程获取到.通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问.  例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;而此时,线程B也企图获取“obj的同步锁” —— 线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。

基本规则

第一条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

第二条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。

第三条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

synchronized 方法

public synchronized void foo1() {
  System.out.println("synchronized methoed");
}
synchronized代码块

public void foo2() {
    synchronized (this) {
    System.out.println("synchronized methoed");
    }
}

synchronized代码块中的this是指当前对象。也可以将this替换成其他对象,例如将this替换成obj,则foo2()在执行synchronized(obj)时就获取的是obj的同步锁。

synchronized代码块可以更精确的控制冲突限制访问区域,有时候表现更高效率

实例锁 和 全局锁
实例锁 -- 锁在某一个实例对象上。如果该类是单例,那么该锁也具有全局锁的概念。实例锁对应的就是synchronized关键字。

全局锁 -- 该锁针对的是类,无论实例多少个对象,那么线程都共享该锁。全局锁对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)。

pulbic class Something {
  public synchronized void isSyncA(){}
  public synchronized void isSyncB(){}
  public static synchronized void cSyncA(){}
  public static synchronized void cSyncB(){}
}

(01) x.isSyncA()与x.isSyncB() 不能被同时访问。因为isSyncA()和isSyncB()都是访问同一个对象(对象x)的同步锁!

(02) x.isSyncA()与y.isSyncA()  可以同时被访问。因为访问的不是同一个对象的同步锁,x.isSyncA()访问的是x的同步锁,而y.isSyncA()访问的是y的同步锁。

(03) x.cSyncA()与y.cSyncB()不能被同时访问。因为cSyncA()和cSyncB()都是static类型,x.cSyncA()相当于Something.isSyncA(),y.cSyncB()相当于Something.isSyncB(),因此它们共用一个同步锁,不能被同时反问。

(04) x.isSyncA()与Something.cSyncA() 可以被同时访问。因为isSyncA()是实例方法,x.isSyncA()使用的是对象x的锁;而cSyncA()是静态方法,Something.cSyncA()可以理解对使用的是“类的锁”。因此,它们是可以被同时访问的。

线程阻塞与唤醒wait,notify,notifyAll
在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

Object类中关于等待/唤醒的API详细信息如下:

notify()       -- 唤醒在此对象监视器上等待的单个线程。

notifyAll()   -- 唤醒在此对象监视器上等待的所有线程。

wait()         -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。

wait(long timeout)      -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。

wait(long timeout, int nanos)  -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

// WaitTest.java的源码
class ThreadA extends Thread{

  public ThreadA(String name) {
    super(name);
  }

  public void run() {
    synchronized (this) {
      System.out.println(Thread.currentThread().getName()+" call notify()");
      // 唤醒当前的wait线程
      notify();
    }
  }
}

public class WaitTest {

  public static void main(String[] args) {

    ThreadA t1 = new ThreadA("t1");

    synchronized(t1) {
      try {
        // 启动“线程t1”
        System.out.println(Thread.currentThread().getName()+" start t1");
        t1.start();

        // 主线程等待t1通过notify()唤醒。
        System.out.println(Thread.currentThread().getName()+" wait()");
        t1.wait();

        System.out.println(Thread.currentThread().getName()+" continue");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

输出

main start t1
main wait()
t1 call notify()
main continue

(01) 注意,图中"主线程" 代表“主线程main”。"线程t1" 代表WaitTest中启动的“线程t1”。 而“锁” 代表“t1这个对象的同步锁”。

(02) “主线程”通过 new ThreadA("t1") 新建“线程t1”。随后通过synchronized(t1)获取“t1对象的同步锁”。然后调用t1.start()启动“线程t1”。

(03) “主线程”执行t1.wait() 释放“t1对象的锁”并且进入“等待(阻塞)状态”。等待t1对象上的线程通过notify() 或 notifyAll()将其唤醒。

(04) “线程t1”运行之后,通过synchronized(this)获取“当前对象的锁”;接着调用notify()唤醒“当前对象上的等待线程”,也就是唤醒“主线程”。

(05) “线程t1”运行完毕之后,释放“当前对象的锁”。紧接着,“主线程”获取“t1对象的锁”,然后接着运行。

t1.wait()是通过“线程t1”调用的wait()方法,但是调用t1.wait()的地方是在“主线程main”中。而主线程必须是“当前线程”,也就是运行状态,才可以执行t1.wait()。所以,此时的“当前线程”是“主线程main”!因此,t1.wait()是让“主线程”等待,而不是“线程t1”!

package thread.Test;

public class NotifyAllTest {

  private static Object obj = new Object();
  public static void main(String[] args) {

    ThreadA t1 = new ThreadA("t1");
    ThreadA t2 = new ThreadA("t2");
    ThreadA t3 = new ThreadA("t3");
    t1.start();
    t2.start();
    t3.start();

    try {
      System.out.println(Thread.currentThread().getName()+" sleep(3000)");
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    synchronized(obj) {
      System.out.println(Thread.currentThread().getName()+" notifyAll()");
      obj.notifyAll();//在此唤醒t1.t2.t3
    }
  }

  static class ThreadA extends Thread{

    public ThreadA(String name){
      super(name);
    }

    public void run() {
      synchronized (obj) {
        try {
          // 打印输出结果
          System.out.println(Thread.currentThread().getName() + " wait");

          //释放obj对象锁
          obj.wait();

          // 打印输出结果
          System.out.println(Thread.currentThread().getName() + " continue");
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }
}

输出:

t1 wait
main sleep(3000)
t3 wait
t2 wait
main notifyAll()
t2 continue
t3 continue
t1 continue

(01) 主线程中新建并且启动了3个线程"t1", "t2"和"t3"。

(02) 主线程通过sleep(3000)休眠3秒。在主线程休眠3秒的过程中,我们假设"t1", "t2"和"t3"这3个线程都运行了。以"t1"为例,当它运行的时候,它会执行obj.wait()等待其它线程通过notify()或额nofityAll()来唤醒它;相同的道理,"t2"和"t3"也会等待其它线程通过nofity()或nofityAll()来唤醒它们。

(03) 主线程休眠3秒之后,接着运行。执行 obj.notifyAll() 唤醒obj上的等待线程,即唤醒"t1", "t2"和"t3"这3个线程。 紧接着,主线程的synchronized(obj)运行完毕之后,主线程释放“obj锁”。这样,"t1", "t2"和"t3"就可以获取“obj锁”而继续运行了!

notify,notifyall与锁的关系

Object中的wait(), notify()等函数,和synchronized一样,会对“对象的同步锁”进行操作。

wait()会使“当前线程”等待,因为线程进入等待状态,所以线程应该释放它锁持有的“同步锁”,否则其它线程获取不到该“同步锁”而无法运行!

OK,线程调用wait()之后,会释放它锁持有的“同步锁”;而且,根据前面的介绍,我们知道:等待线程可以被notify()或notifyAll()唤醒。现在,请思考一个问题:notify()是依据什么唤醒等待线程的?或者说,wait()等待线程和notify()之间是通过什么关联起来的?答案是:依据“对象的同步锁”。

负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。

总之,notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。

线程让步yield
线程让步,使线程从执行状态变为就绪状态,从而让其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是当前线程又进入到“运行状态”继续运行。

yield 与wait

(01) wait()是让线程由“运行状态”进入到“等待(阻塞)状态”,而不yield()是让线程由“运行状态”进入到“就绪状态”。

(02) wait()是会线程释放它所持有对象的同步锁,而yield()方法不会释放锁。

(03) wait是object的方法,yield是Thread的方法

线程休眠 sleep
sleep() 的作用是让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;在线程重新被唤醒时,它会由“阻塞状态”变成“就绪状态”,从而等待cpu的调度执行。

sleep与wait的区别

wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。而sleep()的作用是也是让当前线程由“运行状态”进入到“休眠(阻塞)状态。(这个其实区别不大)

wait()会释放对象的同步锁,而sleep()则不会释放锁

wait是object的方法,sleep是Thread的方法

join
让主线程等待,子线程运行完毕,主线程才能继续运行

interrupt
用来终止处于阻塞状态的线程

@Override
public void run() {
  try {
    while (true) {
      // 执行任务...
    }
  } catch (InterruptedException ie) {
    // 由于产生InterruptedException异常,退出while(true)循环,线程终止!
  }
}

在while(true)中不断的执行任务,当线程处于阻塞状态时,调用线程的interrupt()产生InterruptedException中断。中断的捕获在while(true)之外,这样就退出了while(true)循环

终止处于运行状态的线程

@Override
public void run() {
  while (!isInterrupted()) {
  // 执行任务...
  }
}

通用的终止线程的方式

@Override
public void run() {
  try {
    // 1. isInterrupted()保证,只要中断标记为true就终止线程。
    while (!isInterrupted()) {
      // 执行任务...
    }
  } catch (InterruptedException ie) {
    // 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。
  }
}

线程优先级
java 中的线程优先级的范围是1~10,默认的优先级是5。“高优先级线程”会优先于“低优先级线程”执行。java 中有两种线程:用户线程和守护线程。可以通过isDaemon()方法来区别它们:如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。用户线程一般用户执行用户级任务,而守护线程也就是“后台线程”,一般用来执行后台任务。需要注意的是:Java虚拟机在“用户线程”都结束后会后退出。

每个线程都有一个优先级。“高优先级线程”会优先于“低优先级线程”执行。每个线程都可以被标记为一个守护进程或非守护进程。在一些运行的主线程中创建新的子线程时,子线程的优先级被设置为等于“创建它的主线程的优先级”,当且仅当“创建它的主线程是守护线程”时“子线程才会是守护线程”。

当Java虚拟机启动时,通常有一个单一的非守护线程(该线程通过是通过main()方法启动)。JVM会一直运行直到下面的任意一个条件发生,JVM就会终止运行:

(01) 调用了exit()方法,并且exit()有权限被正常执行。

(02) 所有的“非守护线程”都死了(即JVM中仅仅只有“守护线程”)。

守护进程

(01) 主线程main是用户线程,它创建的子线程t1也是用户线程。

(02) t2是守护线程。在“主线程main”和“子线程t1”(它们都是用户线程)执行完毕,只剩t2这个守护线程的时候,JVM自动退出。

生产者消费者问题
(01) 生产者仅仅在仓储未满时候生产,仓满则停止生产。

(02) 消费者仅仅在仓储有产品时候才能消费,仓空则等待。

(03) 当消费者发现仓储没产品可消费时候会通知生产者生产。

(04) 生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

线程之间的通信

方式:共享内存和消息传递

共享内存:线程A和线程B共享内存,线程A更新共享变量的值,刷新到主内存中,线程B去主内存中读取线程A更新后的变量。整个通信过程必须通过主内存。同步是显式进行的。

如果一个变量是volatile类型,则对该变量的读写就将具有原子性。如果是多个volatile操作或类似于volatile++这种复合操作,这些操作整体上不具有原子性。

volatile变量自身具有下列特性:

[可见性]:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

[原子性]:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。

volatile写:当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。

volatile读:当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

消息传递:消息的发送在消息的接受之前,同步隐式进行。

ThreadLocal

ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的.ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。 如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。

ThreadLocal的一个实现

import java.util.Collections;
import java.util.HashMap;
import java.util.Map; 

/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal { 

    //定义了一个ThreadLocal变量,用来保存int或Integer数据
    private com.lavasoft.test2.ThreadLocal<Integer> tl = new com.lavasoft.test2.ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    }; 

    public Integer getNextNum() {
        //将tl的值获取后加1,并更新设置t1的值
        tl.set(tl.get() + 1);
        return tl.get();
    }
} 

class ThreadLocal<T> {
    private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>()); 

    public ThreadLocal() {
    } 

    protected T initialValue() {
        return null;
    } 

    public T get() {
        Thread t = Thread.currentThread();
        T obj = map.get(t);
        if (obj == null && !map.containsKey(t)) {
            obj = initialValue();
            map.put(t, obj);
        }
        return obj;
    } 

    public void set(T value) {
        map.put(Thread.currentThread(), value);
    } 

    public void remove() {
        map.remove(Thread.currentThread());
    }
}

事实上ThreadLocal是这样做的:

  public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
      ThreadLocalMap.Entry e = map.getEntry(this);
      if (e != null)
        return (T)e.value;
    }
    return setInitialValue();
  }
(0)

相关推荐

  • Java实现监控多个线程状态的简单实例

    实例如下: import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * 测试监控类 * * @author * */ public class WatchThread { /** * 测试函数 * * @throws InterruptedException */ public void testThre

  • 详解三种java实现多线程的方式

    java中实现多线程的方法有两种:继承Thread类和实现runnable接口. 1.继承Thread类,重写父类run()方法 public class thread1 extends Thread { public void run() { for (int i = 0; i < 10000; i++) { System.out.println("我是线程"+this.getId()); } } public static void main(String[] args) {

  • 学习Java多线程之线程定义、状态和属性

    一 .线程和进程 1. 什么是线程和进程的区别: 线程是指程序在执行过程中,能够执行程序代码的一个执行单元.在java语言中,线程有四种状态:运行 .就绪.挂起和结束. 进程是指一段正在执行的程序.而线程有事也被成为轻量级的进程,他得程序执行的最小单元,一个进程可以拥有多个线程,各个线程之间共享程序的内功空间(代码段.数据段和堆空间)及一些进程级的资源(例如打开的文件),但是各个线程都拥有自己的棧空间. 2. 为何要使用多进程 在操作系统级别上来看主要有以下几个方面: - 使用多线程可以减少程序

  • 总结Java中线程的状态及多线程的实现方式

    线程的状态 线程状态图: 说明: 线程共包括以下5种状态. 1. 新建状态(New) : 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread(). 2. 就绪状态(Runnable): 也被称为"可执行状态".线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程.例如,thread.start().处于就绪状态的线程,随时可能被CPU调度执行. 3. 运行状态(Running) : 线程获取CPU权限进行执行.需要注意

  • Java多线程的实现方式比较(两种方式比较)

    先看一下java线程运行时各个阶段的运行状态 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源.一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行.由于线程之间的相互制约,致使线程在运行中呈现出间断性. 在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位.由于线程比进程更小,基本上不拥有系统资源,故对它的

  • 整理总结Java多线程程序编写的要点

    线程状态图 线程共包括以下5种状态. 1. 新建状态(New)         : 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread(). 2. 就绪状态(Runnable): 也被称为"可执行状态".线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程.例如,thread.start().处于就绪状态的线程,随时可能被CPU调度执行. 3. 运行状态(Running) : 线程获取CPU权限进行执行.需要注意的是,

  • 创建java多线程程序

    目录 创建多线程程序的第一种方式:创建Thread类的子类 实现步骤: 创建多线程程序的第二种方式:实现RunnabLe接口 java.Lang.Thread类的构造方法 实现步骤: 实现Runnable接口创建多线程程序的好处: 匿名内部类方式实现线程的创建 Thread类中的常用方法: 获取线程的名称: 设置线程的名称:(了解) 总结: 创建多线程程序的第一种方式:创建Thread类的子类 java.lang.Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类

  • 深入探究Java多线程并发编程的要点

    关键字synchronized synchronized关键可以修饰函数.函数内语句.无论它加上方法还是对象上,它取得的锁都是对象,而不是把一段代码或是函数当作锁. 1,当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一段时间只能有一个线程得到执行,而另一个线程只有等当前线程执行完以后才能执行这块代码. 2,当一个线程访问object中的一个synchronized(this)同步代码块时,其它线程仍可以访问这个object中是其它非synchr

  • Java多线程程序中synchronized修饰方法的使用实例

    在Java 5以前,是用synchronized关键字来实现锁的功能. synchronized关键字可以作为方法的修饰符(同步方法),也可作用于函数内的语句(同步代码块). 掌握synchronized,关键是要掌握把那个东西作为锁.对于类的非静态方法(成员方法)而言,意味着要取得对象实例的锁:对于类的静态方法(类方法)而言,要取得类的Class对象的锁:对于同步代码块,要指定取得的是哪个对象的锁.同步非静态方法可以视为包含整个方法的synchronized(this) { - }代码块.  

  • java多线程中的异常处理机制简析

    在java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉.这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束.但是线程依然有可能抛出unchecked exception,当此类异常跑抛出时,线程就会终结,而对于主线程和其他线程完全不受影响,且完全感知不到某个线程抛出的异常(也是说完全无法catch到这个异常

  • Java多线程的调度_动力节点Java学院整理

    有多个线程,如何控制它们执行的先后次序?         方法一:设置线程优先级. java.lang.Thread 提供了 setPriority(int newPriority) 方法来设置线程的优先级,但线程的优先级是无法保障线程的执行次序的,优先级只是提高了优先级高的线程获取 CPU 资源的概率.也就是说,这个方法不靠谱.       方法二:使用线程合并. 使用 java.lang.Thread 的 join() 方法.比如有线程 a,现在当前线程想等待 a 执行完之后再往下执行,那就

  • Java 多线程并发编程_动力节点Java学院整理

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线程:表示程序的执行流程,是CPU调度执行的基本单位:线程有自己的程序计数器.寄存器.堆栈和帧.同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源. 2.Java标准库提供了进程和线程相关的API,进程主要包括表示进程的jav

  • java多线程入门知识及示例程序

    为什么需要多线程?模型的简化,如某些程序是由多个相对独立任务的运行: 图形界面的出现,输入.输出的阻塞 多核CPU的更好利用 异步行为的需要 Java多线程的特性: 程序的入口main本身是一个线程 线程是并发的,无序执行的 线程内部是顺序执行的 共享数据 Java多线程的风险: 安全风险:由于线程的操作顺序是不确定的,某些在单线程下能运行的程序到多线程下会出现意外的结果. 性能风险:服务器的吞吐量.响应性.资源消耗 Java多线程API: Java可以通过两种形式创建线程:一.实现Runnab

  • Java多线程的其他知识_动力节点Java学院整理

    一.线程组 /** * A thread group represents a set of threads. In addition, a thread * group can also include other thread groups. The thread groups form * a tree in which every thread group except the initial thread group * has a parent. * <p> * A thread

  • Java多线程中不同条件下编写生产消费者模型方法介绍

    简介: 生产者.消费者模型是多线程编程的常见问题,最简单的一个生产者.一个消费者线程模型大多数人都能够写出来,但是一旦条件发生变化,我们就很容易掉进多线程的bug中.这篇文章主要讲解了生产者和消费者的数量,商品缓存位置数量,商品数量等多个条件的不同组合下,写出正确的生产者消费者模型的方法. 欢迎探讨,如有错误敬请指正 生产消费者模型 生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品.生产消费者模式

随机推荐