线程是程序里不同的执行路径
起一个新的线程,执行在run方法里面的程序
一、构造方法
推荐用实现接口,因为继承只能单继承
1.实现Runnable接口
package threadText;
public class TestThread1 {
public static void main(String[] args){
Runner1 r = new Runner1();
//r.run();这样是方法的调用,不是线程
Thread t = new Thread(r);//必须实例化一个Thread
t.start();//必须调用start开始一个新的线程
for(int i=0; i<100; i++){
System.out.println("main"+ i);
}
}
}
class Runner1 implements Runnable{//比如重写run方法
public void run(){
for(int i=0; i<100; i++){
System.out.println("Runner" + i);
}
}
}
2.继承Thread类
package threadText;
public class TestThread2 {
public static void main(String[] args){
Runner2 r = new Runner2();
r.start();//因为r本身就是Thread类,所以可以直接调用
for(int i = 0; i<100; i++){
System.out.println("Main:" + i);
}
}
}
class Runner2 extends Thread{//继承Thread类
public void run(){
for(int i=0; i<100; i++){
System.out.println("Runner" + i);
}
}
}
二、sleep、join、 yeild方法
1.sleep方法
线程退出的一种方式,但是更好的方法是写一个flag
Thread静态方法,会抛出被打断的异常
package threadText;
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(); //打断子进程
}
}
class MyThread extends Thread{
public void run(){
while(true){
System.out.println("===" + new Date() + "===");
try{
sleep(1000);
} catch (InterruptedException e){
return;//如果被打断结束子进程
}
}
}
}
2.join方法
合并某个线程
package threadText;
public class TestJoin {
public static void main(String[] args){
MyThread2 t2 = new MyThread2("abcd");
t2.start();
try{
t2.join();//将t2合并到线程,即执行完t2才执行主线程
}catch(InterruptedException e){
}
for(int i = 0; i<10; i++){
System.out.println("i am main Thread!");
}
}
}
class MyThread2 extends Thread{
MyThread2(String s){//构造方法,把s传递给super即Thread名称
super(s);
}
public void run(){
for(int i = 0; i<10; i++){
System.out.println("i am:" + getName() );//getName是Thread里的方法
try{
sleep(1000);
}catch(InterruptedException e){
return;
}
}
}
}
结果会执行完t2再执行主线程
3.yield方法
让出cpu让别的先执行
4.设置优先级
’
package threadText;
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.start();
t2.start();
}
}
class T1 implements Runnable{
public void run(){
for(int i = 0; i<100; i++){
System.out.println("This is T1"+ i);
}
}
}
class T2 implements Runnable{
public void run(){
for(int i = 0; i<100; i++){
System.out.println("T2" + i);
}
}
}
三、线程同步
一个线程在执行的过程中不会被另一个线程打断
package threadText;
public class TestSync implements Runnable{
Timer timer = new Timer();
public static void main(String[] args){
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();//两个访问的都是同一个timer文件
t2.start();
}
public void run(){
timer.add(Thread.currentThread().getName());//获得当前线程的名字传入
}
}
class Timer{
private static int num = 0;
public void add(String name){
synchronized(this){//锁定这些方法,线程在使用它时被锁定,别的方法暂时不能用
num++;
try{
Thread.sleep(100);
}catch(InterruptedException e){}
System.out.println(name+ "当前是第"+ num + "使用timer线程的");
}
}
}
。
锁定了当前的对象后,,睡眠的时候别的进程也不会再执行,不会再出现混乱
死锁
锁定时粒度太小,会使线程无法结束
/*
* 死锁的产生是因为两个线程锁住对方完成的条件之一
* 解决方法增加锁的粒度,即把整个方法都锁住,而不要锁小的方法
*/
package threadText;
public class DeadLock implements Runnable{
public int flag = 1;
static Object o1 = new Object();
static Object o2 = new Object();
public void run(){//重写run方法
System.out.println("flag:" + flag);
if(flag == 1){//用if区别两个线程的run方法
synchronized(o1){
try{
Thread.sleep(10000);
}catch(Exception e){
e.printStackTrace();
}
synchronized(o2){
System.out.println("1");//在锁死o2该线程完成
}
}
}
if(flag == 0){
synchronized(o2){//上来就把o2锁住,两个线程谁也无法完成
try{
Thread.sleep(10000);
}catch(Exception e){
e.printStackTrace();
}
synchronized(o1){
System.out.println("0");
}
}
}
}
public static void main(String[] args){
DeadLock td1 = new DeadLock();
DeadLock td2 = new DeadLock();
td1.flag = 1;
td2.flag = 0;
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.start();
t2.start();
}
}
四、生产者消费者问题
package threadText;
public class ProducerConsumer {
public static void main(String[] args){
SynStack ss = new SynStack();
Producer p = new Producer(ss); //两个线程同一个框
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(c).start();
}
}
class WoTou{
int id;
WoTou(int id ){
this.id = id;
}
public String toString(){//重写toString方法,方便显示
return "WoTou" + id;
}
}
class SynStack{//先进后出,用栈模拟篮子
int index = 0;
WoTou[] arrMT = new WoTou[6];
public synchronized void push(WoTou wt){//同步,防止这个方法两条语句打断
while(index == arrMT.length){//篮子满了就停止
try{
this.wait();//当前锁定在这个对象的线程停止,必须是锁定了以后才能wait
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.notify();//叫醒正在wait上的线程
arrMT[index] = wt;
index++;
}
public synchronized WoTou pop(){//取馒头
while(index == 0){//没有馒头了等待
try{
this.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.notify();
index--;
return arrMT[index];
}
}
class Producer implements Runnable{//生产者类
SynStack ss = null;
Producer(SynStack ss){//构造方法,指定一个篮子生产
this.ss = ss;
}
public void run(){//生产馒头
for(int i = 0; i<20; i++){
WoTou wt = new WoTou(i);
ss.push(wt);//装入篮子
System.out.println("生产了:" + wt);
try{
Thread.sleep(1000);
}catch(InterruptedException e ){
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{//生产者类
SynStack ss = null;
Consumer(SynStack ss){//构造方法,指定一个篮子拿出
this.ss = ss;
}
public void run(){//消费馒头
for(int i = 0; i<20; i++){
WoTou wt = ss.pop();
System.out.println("消费了:"+ wt);
try{
Thread.sleep(1000);
}catch(InterruptedException e ){
e.printStackTrace();
}
}
}
}