1、线程的基本概念
例子:
分析:
2、线程的创建和启动
第一种线程的创建:
定义一个线程类来实现Runner接口
例子:
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {
public static void main(String[] args) {
Runner1 runner1 = new Runner1();
Thread myThread = new Thread(runner1);
myThread.start();//这行注释掉的话,线程就不会执行。
for(int i=0;i<100;i++) {
System.out.println("Main Thread:-----" + i);
}
}
}
class Runner1 implements Runnable{
public void run() {
for(int i = 0;i<100;i++) {
System.out.println("Runner1:" + i);
}
}
}
运行结果:
我们会发现,主线程,和子线程是交替执行的。
但是呢,要注意:
但是若是直接调用run方法,是方法调用,两者之间天壤之别,只有执行完成一个才会去执行另一个。
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {
public static void main(String[] args) {
Runner1 runner1 = new Runner1();
//Thread myThread = new Thread(runner1);
runner1.run();
//myThread.start();//这行注释掉的话,线程就不会执行。
for(int i=0;i<100;i++) {
System.out.println("Main Thread:-----" + i);
}
}
}
class Runner1 implements Runnable{
public void run() {
for(int i = 0;i<100;i++) {
System.out.println("Runner1:" + i);
}
}
}
证明如下:
第二种线程的创建:
定义一个Thread的子类并重写其run方法。
例子:
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for(int i=0;i<100;i++) {
System.out.println("Main Thread:-----" + i);
}
}
}
class MyThread extends Thread{
public void run() {
for(int i = 0;i<100;i++) {
System.out.println("Runner1:" + i);
}
}
}
此时,已经新建一个MyThread类继承自Thread类,所以就不用new一个Thread 的对象出来了,而只需要new一个MyThread的子对象。然后调用其start()方法。
执行结果:
我们发现和第一种创建线程的结果是一样的,也是交替执行。但是两个线程分得到的时间片并不一定是相同的。
两个方式有什么区别呢?继承Thread类的方式(第二种方式)比较死,只能从一个类继承,第一种方式呢?比较灵活实现接口,还可以从其他类继承。只要能实现接口,就不要从Thread类继承。
线程状态转换:
1、sleep方法:
package com.zhj.www;
import java.util.*;
public class TestInterrupt {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
try {
Thread.sleep(10000);//主线程睡眠
}catch (InterruptedException e) {}
//thread.interrupt();//睡着的时候打断,太粗暴了//为什么不用它呢?
thread.flag = false;
}
}
class MyThread extends Thread{
boolean flag = true;
public void run() {
while(flag) {
System.out.println("==="+new Date()+"===");
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
运行结果:
2、join方法:
栗子:
package com.zhj.www;
public class TestJoin {
public static void main(String[] args) {
MyThread2 t1 = new MyThread2("abcdef");
t1.start();
try {
t1.join();//合共
}catch (InterruptedException e) {}
for(int i = 1;i<=10;i++) {
System.out.println("I am main thread");
}
}
}
class MyThread2 extends Thread{
public MyThread2(String s) {
super(s);
}
public void run() {
for(int i = 0; i<=10;i++) {
System.out.println("I am "+ getName()+" (i:)"+i);
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
运行结果:
3、yield方法:
package com.zhj.www;
import java.util.*;
public class TestYield {
public static void main(String[] args) {
MyThread3 t1 = new MyThread3("t1");
MyThread3 t2 = new MyThread3("t2");
t1.start();
t2.start();
}
}
class MyThread3 extends Thread{
MyThread3(String s) {
super(s);
}
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName()+": "+i);
if(i%10 == 0) {
yield();
}
}
}
}
运行结果:
t1到10的倍数切换t2,t2到10的倍数切换t1;
上例子:
package com.zhj.www;
public class TestPriority {
public static void main(String[] args) {
Thread t1 = new Thread(new T1());
Thread t2 = new Thread(new T2());
t1.setPriority(Thread.NORM_PRIORITY+3);//t1得到的执行时间长
t1.start();
t2.start();
}
}
class T1 implements Runnable{
public void run() {
for(int i =0;i< 100;i++) {
System.out.println("T1: "+ i);
}
}
}
class T2 implements Runnable{
public void run() {
for(int i =0;i< 100;i++) {
System.out.println("-------T2: "+ i);
}
}
}
运行一下:
可以发现:t1比t2运行的时间长。
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
额外的栗子:
--------------------------------------------------------------------------------------
TestThread2.java
package com.zhj.www;
public class TestThread2 {
public static void main(String[] args) {
Runner2 r = new Runner2();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
class Runner2 implements Runnable{
public void run() {
for(int i = 0; i <= 30; i++) {
System.out.println("No: "+ i);
}
}
}
运行一下:
TestThread3.java
package com.zhj.www;
public class TestThread3 {
public static void main(String[] args) {
Runner3 runner3 = new Runner3();
Thread thread = new Thread(runner3);
thread.start();
}
}
class Runner3 implements Runnable {
public void run() {
for(int i = 0; i<30;i++) {
if(i%10 == 0 && i != 0) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
}
System.out.println("No. " + i);
}
}
}
当i 是 10的倍数时,会睡眠2s。
运行结果:
TestThread4.java
package com.zhj.www;
public class TestThread4 {
public static void main(String[] args) {
Runner4 r = new Runner4();
Thread t = new Thread(r);
t.start();
for(int i = 0; i< 100000 ; i++) {
if(i%10000 == 0 & i>0) {
System.out.println("in thread main i =" + i);
}
}
System.out.println("Thread mian is over");
r.shutDown();
}
}
class Runner4 implements Runnable{
private boolean flag = true;
public void run() {
int i = 0;
while(flag == true) {
System.out.println(" " + i++);
}
}
public void shutDown() {
flag = false;
}
}
主要:怎么让一个正常执行的线程停止。
run方法结束,线程就结束。
运行结果:
TestThread5.java(关于join方法)
package com.zhj.www;
public class TestThread5 {
public static void main(String[] args) {
Runner5 r = new Runner5();
Thread thread = new Thread(r);
thread.start();
try {
thread.join();
}catch (InterruptedException e) {}
for(int i = 0; i<50;i++) {
System.out.println("主线程:"+ i);
}
}
}
class Runner5 implements Runnable{
public void run(){
for(int i= 0 ;i<50;i++) {
System.out.println("SubThread: " + i);
}
}
}
运行结果:
TestThread6.java
package com.zhj.www;
public class TestThread6 {
public static void main(String[] args) {
Thread thread = new Runner6();
thread.start();
for(int i = 0; i<50 ;i++) {
System.out.println("MainThread: "+ i);
}
}
}
class Runner6 extends Thread{
public void run() {
System.out.println(Thread.currentThread().isAlive());
for(int i = 0;i<50;i++) {
System.out.println("SubThread: " + i);
}
}
}
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
线程同步
自身是一个线程类。
分析内存:
分析完内存,我们运行一下:
package com.zhj.www;
public class TestSync implements Runnable{
Timer timer =new Timer();
public static void main(String[] args) {
TestSync testSync = new TestSync();
Thread t1 = new Thread(testSync);
Thread t2 = new Thread(testSync);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
public void run() {
timer.add(Thread.currentThread().getName());
}
}
class Timer{
private static int num = 0;
public void add(String name ) {
num++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
System.out.println(name+",你是第"+num+"个使用timer的线程");
}
}
运行一下:
结果为什么是这样呢?感觉哪里不对。
线程在执行这个方法时,被另一个线程打断了。写sleep,是为了
放大这个效果。
怎么解决呢?
在执行的时候,锁定当前对象。一个执行进入到锁住区域时,另一个
线程不可打扰。
如下:
public void add(String name ) {
synchronized (this) {
num++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
System.out.println(name+",你是第"+num+"个使用timer的线程");
}
}
互斥锁。
另外简便的写法:
public synchronized void add(String name ) {
//synchronized (this) {
num++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
System.out.println(name+",你是第"+num+"个使用timer的线程");
//}
}
执行这个方法时,锁住当前对象。
睡着的时候,依然抱着这把锁,其他的人如果要执行这个方法必须等他执行完这个方法。