说到线程首先要提起进程,进程是什么?进程就是在机器中的一次运行,但是不仅包括代码,还需要包括一些系统资源,例如:cpu,内存,i/o的端口等等。
线程是进程更小的单位,它不能单独存在 ,必须栖息在进程中。
java支持多线程,可以将很多的功能放在一起 ,举个例子:在一个游戏中界面上显示着滚动的时间,如果是单线程,那么你在玩的时候会很卡,因为它必须先完成其中的某一个功能在实现另一个,比如先进行时间的滚动,在进行游戏的体验(或者先游戏,在时间所以这是不好的影响用户体验)。多线程可以支持这些所有的功能同时一起实现(只是你看上去是这样的,但是在运行的时间上并不是一起的,只是时间太短了让人们感觉是一起的)。
这张图中还缺少一个最重要的stop(),不管线程处于什么状态只要stop(),那么这个线程就死亡了。
当然其中一些还是很后面的东西,先来最简单的。如何新建一个线程呢,有两种方法:
第一种就是继承Thread这个类:
package com.thread;
public class thread1 extends Thread {//仅仅只是举个例子代码内容可以不看
int i;
public void run()//必须实现run()的内容这就是这个线程需要做的事情
{
synchronized(this)
{
for(i=0;i<=100;i++)
{
System.out.println(i);
}
if(i==50)
{
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {//这里面是如何使用这个线程
// TODO Auto-generated method stub
thread1 c=new thread1();
c.start();
}
} 第二种就是继承Runnable这个接口。
package com.thread;
public class thread3 implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("qwe");
}
public static void main(String[] args) {//这里面是如何使用这个线程
// TODO Auto-generated method stub
thread3 c=new thread3();
Thread thread=new Thread(c);
thread.start();
}
}
这两个线程的使用方式是不同的.
线程可以通过这些函数来控制线程:
start()启动线程对象
run()必须重写这个才能实现线程
yield()强制终止线程的执行
isAlive()检测线程是否还在活动
sleep(int second)强行让线程休眠一段时间可以添加参数
currentThread()这个可以获得当前正在运行的线程。
现在来讲讲对线程的基本控制:
1、结束线程。
这个其实很简单,只要一个stop()就可以解决,stop()并不让线程处于挂起状态(就是可以继续运行)而是直接死亡了。
2、检测线程
通过之前说的isAlive()来检测。
3、挂起线程
这个有很多中方式
(1)sleep(int second)这个是最简单的,只要对象使用这个函数设置时间就行,但是真正的时间并不是这个数字因为线程的竞争性,所以这个只能说明这个时间是停止的其他的管不了
(2)suspend()这个是强行把线程挂起, 他自己不能当用本身来重新启动,它需要靠其他的线程来重新启动它。使用resume()这个来启动它。
package com.thread;
public class xyz implements Runnable {
@SuppressWarnings("deprecation")
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("qwe");
Thread.currentThread().suspend();
System.out.println("qw");
}
}
package com.thread;
public class usexyz {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
// TODO Auto-generated method stub
xyz c=new xyz();
Thread w=new Thread(c);
w.start();
w.resume();
}
}
就像这个样子,但是有一个很大的问题这么用了以后很有可能造成死锁,所以不推荐使用(死锁我会做介绍但是具体实现是操作系统的事情所以你们懂的)。
(3)join()会让当前的线程停止先去执行使用join的那个线程
package com.thread;
public class qwe extends Thread {
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println(i);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
qwe c=new qwe();
c.start();
for(int i=10;i<20;i++)
{
try {
c.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(i);
}
}
}
你们可以自己去试试看 有点意思的。
同步的问题
两个线程应该怎么通信呢 ,肯定是使用管道流
package com.stream;
import java.io.*;
public class mtReader extends Thread {
private PipedInputStream input;
public mtReader(PipedInputStream o)
{
input=o;
}
public void run()
{
String s;
BufferedReader d=new BufferedReader(new InputStreamReader(input));
while(d!=null)
{
try {
s=d.readLine();
if(s!=null)System.out.println(s);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package com.stream;
import java.io.*;
public class mtWriter extends Thread {
private PipedOutputStream output;
private String mess[]={"monday","tuesday","wednesday","thursday","friday","saturday","sunday"};
public mtWriter (PipedOutputStream o)
{
output = o;
}
public void run()
{
int i;
PrintStream p=new PrintStream(output);
for(i=0;i<mess.length;i++)
{
p.println(mess[i]);
p.flush();
}
p.close();
}
}
package com.stream;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class qwe {
public void go()
{
try {
PipedInputStream input=new PipedInputStream();
PipedOutputStream output=new PipedOutputStream(input);
new mtWriter(output).start();
new mtReader(input).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
qwe c=new qwe();
c.go();
}
}
就是这么简单。
可是你要想到如果这样的话两个或者多个线程同时对一个变量进行读取怎么办,这肯定会造成很大的问题,甚至是错误。
所以为了避免出现这样的情况那么就会引入一个叫互斥锁的概念.
用synchronized来声明一个方法或者一段代码都是比较好的选择(但是如果遇到很多很多线程这个方法可能就比较没有可行性了,所以只要控制住为什么要使用的本质就可以了,本质就是对于共用变量的控制就可以了,这个方法在操作系统里面有讲所以这里不展开了。)
某些书上说这个的参数只能是this这个是不确切的,可以使用Object的对象。
package com.thread;
public class thread1 extends Thread {
int i;
public void run()
{
synchronized(this)
{
for(i=0;i<=100;i++)
{
System.out.println(i);
}
if(i==50)
{
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
package com.thread;
public class thread2 extends Thread {
public static void main(String[] args) {
// TODO Auto-generated method stub
thread1 c=new thread1();
synchronized(c)
{
c.start();
}
}
}
这样就用起来比较简单了
死锁:
就是当一个线程需要另一个线程的锁才能打开,另一个线程需要这个线程的锁才能运行,那么这两个线程就会无限循环下去。知道机子废掉。。。
所以在设计的时候需要避免这个。具体的实现请看操作系统的书。
线程的交互:
两个看似无关的线程在使用上可能在使用上有关联,例如有两个线程生产者和消费者。他们有一个公共的区域就是缓存,但是缓存只能存一次数据,就是如果不把数据拿出去那么就不能放进去。这样的话 如果生产者很快,消费者的消费很慢,那么消费者有一部分数据将会无法取到,如果生产者很慢,消费者很快,那么消费者会取到很多重复的东西。
因为需要解决这个问题。
那么可以使用wait(),和notify(),notifyAll()来解决。(他们必须在synchronized的内部使用否则报错)。
wait()的作用是把当前对象的锁拿掉,那么同样运行的这个代码的时候会因为无权利而无法运行。
notify() 是吧没有的锁加回来,但是它只是在sychronized这个段运行完了才加进去 并不是一使用就加入的。
public class MyThreadPrinter2 implements Runnable {
private String name;
private Object prev;
private Object self;
private MyThreadPrinter2(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (prev) {
synchronized (self) {
System.out.print(name);
count--;
self.notify();
}
try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);
MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);
new Thread(pa).start();
new Thread(pb).start();
new Thread(pc).start(); }
}
就这么多 。。。。。看书