多线程(Multi-Threading)
Creating threads in Java
Two things to do to create threads in java:
(1) Create a task (object)
//Creating a task
public class TaskClass implements Runnable {
public TaskClass() { ... }
//Implement the run method in Runnable
void run() {
//things to do in the task }
}
//Runnable interface
public interface Runnable {
void run();
}
(2) Create a thread and combine the task with the thread (object)
1 way
//Create a task class
public class TaskClass implements Runnable {
public TaskClass(...) { ... }
//Implement the run method in Runnable
void run() {
//things to do in the task
}
}
public class ThreadDemo{
public void someMethod(){
//Create an instance of TaskClass
TaskClass task=new TaskClass(...);
//Create a thread
Thread thread=new Thread(task);
//Start a thread
thread.start();
}
}
2 way
//Custom thread class
public class CustomThread extends Thread {
public CustomThread( ) { ... }
//Override the run method in Runnable
void run() {
//things to do in the task
}
}
public class ThreadDemo{
public void someMethod(){
//Create a thread
CustomThread thread1=new CustomThread( );
//Start a thread
thread1.start();
//Create another thread
CustomThread thread2=new CustomThread( );
//Start a thread
thread2.start();
}
}
main Thread
When a program starts, the main Thread automatically starts
The default name of the Thread: main with priority 5
public static void main(String[] args){
System.out.println("Current thread: " + Thread.currentThread());
Thread.currentThread().setName("MyThread");
System.out.println("After name change: " + Thread.currentThread());
}
Example: create threads
public class ThreadDemo1 {
public static void main(String[] args) {
String hw= “do home work”;
String tv= “watch TV”;
DoSomething doHW= new DoSomething( hw );
DoSomething watchTV = new DoSomething( tv );
}
}
public class DoSomething {
private String doWhat;
public DoSomething(String aThing) {
this.doWhat = aThing;
doIt();
}
public void doIt(){
for (int i=0;i<5;i++)
System.out.println(doWhat+": "+i);
}
}
并没有使用多线程
Create threads (solution 1)
public class ThreadDemo1 {
public static void main(String[] args) {
DoSomething doHW= new DoSomething("do home work");
DoSomething watchTV = new DoSomething(“watch TV");
Thread hwThread= new Thread(doHW);
Thread tvThread = new Thread(watchTV);
hwThread.start();
tvThread.start();
}
}
public class DoSomething implements Runnable {
private String doWhat;
public DoSomething(String aThing) {
this.doWhat = aThing;
} public void run(){
for (int i=0;i<5;i++)
System.out.println(doWhat+": "+i);
}
}
Create threads solution 2
public class ThreadDemo2 extends Thread {
String doThing;
ThreadDemo2(String doWhat){
this.doThing=doWhat;
}
public static void main(String[] args) {
String hw= "do home work";
String tv= "watch TV";
ThreadDemo2 thread1=new ThreadDemo2(hw);
ThreadDemo2 thread2=new ThreadDemo2(tv);
thread1.start();
thread2.start();
}
public void run() {
for(int i=0;i<5;i++)
System.out.println(doThing+": "+i);
}
}
Control a Thread
public static void yield():
Causes the currently executing thread object to temporarily pause
Allow other threads to execute(执行)
aThread.yield();
t1.yield();
t2.sleep(1000);
static void sleep(long millis):
Causes the currently executing thread to sleep (block) for the specified number of milliseconds
If the thread is blocked by sleep or wait, an InterruptedException is thrown
try {
aThread.sleep(1000);
//sleep for 1 second
} catch (InterruptedException ex) {
//do sth…
}
interrupt():
Does not stop a thread Set "interrupted" status to true Why interrupt?
After interrupt is set, we can take actions
isInterrupted():
Tests whether this thread has been interrupted.
The interrupted status of the thread is unaffected by this method.
if(isInterrupted()){
Action
}
interrupted():
Tests whether the current thread has been interrupted.
The interrupted status of the thread is cleared by this method.
Returns: true if the current thread has been interrupted; false otherwise.
public class ThreadDemo2 extends Thread {
String doThing;
ThreadDemo2(String doWhat){
this.doThing=doWhat;
}
public static void main(String[] args) {
String hw= "do home work";
String tv= "watch TV";
ThreadDemo2 thread1=new ThreadDemo2(hw);
ThreadDemo2 thread2=new ThreadDemo2(tv);
thread1.start();
thread2.start();
}
public void run() {
for(int i=0;i<5;i++) {
System.out.println(doThing+": "+i);
this.yield();
}
}
}
public class ThreadDemo2 extends Thread {
String doThing;
ThreadDemo2(String doWhat){
this.doThing=doWhat;
}
public static void main(String[] args) {
String hw= "do home work";
String tv= "watch TV";
ThreadDemo2 thread1=new ThreadDemo2(hw);
ThreadDemo2 thread2=new ThreadDemo2(tv);
thread1.start();
thread2.start();
}
public void run() {
for(int i=0;i<5;i++) {
System.out.println(doThing+": "+i);
try {
this.sleep(10);
} catch (InterruptedException ex) {
System.out.println(“sth wrong”);
}
}
}
}
Ping Pong Sleep
public class PingPongSleep extends Thread{
private String word;
private int delay;
public PingSleep(String whatToSay, int delayTime){
word = whatToSay;
delay = delayTime;
}
public void run(){
for( int i=0; i<5; i++){
System.out.print(word + " ");
try{
Thread.sleep(delay);
} catch (InterruptedException e){
System.err.println(e);
}
}
}
public static void main(String[ ] args){
Thread ping = new PingPongSleep("ping", 500);
Thread pong = new PingPongSleep("PONG", 1000);
ping.start();
pong.start();
}
}
Ping Pong Interruption
public void run(){
for(int i=1;i<=2;i++)
System.out.println( i+": "+word+" isInterrupted? "+ isInterrupted() );
}
public static void main(String[ ] args){
Thread ping = new PingPongInterrup("ping");
Thread pong = new PingPongInterrup("PONG");
ping.start();
pong.start();
pong.interrupt();
}
}
多线程不能控制顺序,所以前面1,2的顺序无关紧要;且PONG.interrupted是TRUE;
public void run(){
for(int i=1;i<=2;i++)
System.out.println( i+": "+word+" interrupted? "+ interrupted() ) ;
}
public static void main(String[] args){
Thread ping = new PingPongInterrup("ping");
Thread pong = new PingPongInterrup("PONG");
ping.start();
pong.start();
pong.interrupt();
}
}
第二个PONG为false
join(long millis)
Waits at most millis milliseconds for this thread to finish
A timeout of 0 means to wait forever until the thread die
InterruptedException is thrown
You can only “join” a thread before it is selected by the processer
try{
aThread.start();
aThread.join();
}catch(InterruptedException e){
...
}
public class PingPongJoin extends Thread{
private String word;
private int delay;
public PingPongJoin(String whatToSay, int delayTime){
word = whatToSay;
delay = delayTime;
}
public void run(){
for (int i = 0; i < 5; i++){
System.out.print(word + " ");
try {
Thread.sleep(delay);
} catch (InterruptedException e){
}
}
}
public static void main(String[] args){
Thread ping = new PingPongJoin("ping", 500);
Thread pong = new PingPongJoin("PONG", 500);
ping.start(); // ping started
try {
ping.join(); //确保输出结果会是5个ping一直在前面
} catch (InterruptedException e){
}
pong.start();
}
}
Output: ping ping ping ping ping PONG PONG PONG PONG PONG
Synchronization
Two or more threads share the same resource Synchronized method:
To make a method synchronized: add the synchronized keyword to its declaration
When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object
class CallMe{
void call(String msg){
System.out.print( "[" + msg) ;
try{
Thread.sleep(1000);
} catch(InterruptedException e){
System.out.println("Interrupted");
}
System.out.println("]");
}
}
public class PingPongSyn extends Thread{
private String w;
static Callme target;
public PingPongSyn(String whatToSay){
w = whatToSay;
}
public void run(){
target.call(w);
}
public static void main(String[] args){
target = new CallMe();
Thread ping = new PingPongSyn("ping");
Thread pong = new PingPongSyn("PONG");
ping.start();
pong.start();
}
}
suppose:[ping] [PONG]
Actual output:[ping[PONG]
ping went to sleep at this point PONG got a chance to print.
class CallMe{
synchronized void call(String msg){
System.out.print("[" + msg); try { Thread.sleep(1000);
} catch(InterruptedException e){
System.out.println("Interrupted");
}
System.out.println("]");
}
}
The method (common resource) will block other threads when it is called by a thread
public static void main(String[] args){
target = new Callme();
Thread ping = new PingPongSynJoin("ping");
Thread pong = new PingPongJoin("PONG");
ping.start();
try{
ping.join(); //the main thread waits until ping finishes
} catch(InterruptedException e){
}
pong.start();
}
}
Difference between join() and synchronized
多线程的同步机制对资源加锁,使得只有一个线程可以操作,同步用于解决多线程同时访问某一个资源出现的问题。
join用于主线程等待子线程运行完毕它的run方法,再继续执行下面的代码。
Lock Objects
ReentrantLock myLock=new ReentrantLock();
myLock.lock();
try {
critical section //临界区
} finally {
myLock.unlock();
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CallMe2 {
private Lock messageLock=new ReentrantLock(); //Locked for one thread only
public void call(String msg){
messageLock.lock();
try{
System.out.print("[" + msg);
Thread.sleep(1000);
System.out.println("]");
} catch(InterruptedException e){
System.out.println("Interrupted");
} finally{
messageLock.unlock();
}
}
}
Condition Objects
In the previous example,
if we only want to print out “pxxx” only. What’s wrong with this solution:
if((w.toUpperCase()).charAt(0)=='P'){
//do something
target.call(w);
}
We can also specify some conditions for entering a critical section.
private Condition lockCondition;
lockCondition=lock.newCondition();// Create a condition, and attach it with a lock
while(//condition not satisfied) //Block the thread if the condition is not satisfied. Meanwhile another thread can access the critical section
lockCondition.await();
…
lockCondition.signalAll(); // Give the blocked threads another chance
Inter-thread Communication
Polling problem(轮询问题):
A loop that is used to check some condition repeatedly.
Once the condition is true, appropriate action is taken
This wastes CPU time
To avoid polling, Java includes an elegant inter-process communication mechanism via the wait( ), notify( ), and notifyAll( ) methods.
All three methods can be called only from within a synchronized method The rules:
wait( ) tells the calling thread to give up the monitor and go to sleep until some other thread calls notify( )
notify( ) wakes up the first thread that called wait( ) on the same object.
notifyAll( ) wakes up all the threads that called wait( ) on the same object
class Car {
int n;
boolean carAvailable = false; // A flag that indicates car availability
synchronized int get(){
if(!carAvailable) { // Check car availability
try {
wait(); // Stop getting if car is not available
} catch(InterruptedException e) {
}
} System.out.println("Got Car: " + n); // Get one if car is available
carAvailable=false; // Change flag
notify(); // Wakeup other threads
return n;
}
synchronized void make(int n){
if(carAvailable) { // Check car availability
try {
wait(); //Stop making if car is already available
} catch(InterruptedException e) {
}
}
this.n = n; // Make one if car is available
System.out.println("Made Car: " + n);
carAvailable=true; // Change flag
notify(); // Wakeup other threads
}
}