java实现多线程有两种方法:
一种是继承Thread类
如下面例子:
public class TestThread extends Thread {
//实现多线程方法一:继承Thread类,并重载run方法
public void run(){
//要将一段代码在一个新的线程上运行,该代码应写在run函数中
while(true){
System.out.println(Thread.currentThread().getName() + "is running...");
}
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
//启动一个新的线程,不是直接调用Thread类子类对象的run方法,
//而是调用Thread类子类对象的start方法,Thread类对象的start方法
//将产生新的线程,并在该线程上运行该Thread类对象中的run方法,根据
//多态性 实际上运行的是Thread子类的run方法
TestThread testThread = new TestThread();
testThread.start();
while(true){
System.out.println("main thread is running...");
}
}
}
方法二是:实现接口Runnable中的run函数
如下列所示
//实现多线程方法二:实现Runnable接口,重载run函数,
//大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,
//那么应使用 Runnable 接口。这很重要,
//因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。
public class TestThread implements Runnable {
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + "is running......");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
TestThread testThread = new TestThread();//创建TestThread类的一个实例
Thread thread = new Thread(testThread);//创建一个Thread类的实例
thread.start();//使线程进入runnable状态
while(true){
System.out.println("main thread is running...");
}
}
2.这两种方法的区别:实现Runnable接口适合多个相同的程序代码访问处理同一资源
如下列所示:
//四个售票窗口售同一中车票,总共有100张,要求这四个售票多线程进行
public class TicketRunnable implements Runnable {
private int tickets = 100;
public void run() {
while(true){
if(tickets > 0){
System.out.println(Thread.currentThread().getName() +
" is saling ticket " + tickets--);
}
}
}
}
public class TicketRunnableDemo {
public static void main(String[] args){
//创建了四个线程,每个线程调用了同一各TicketRunnable对象中run方法,
//访问的是同一个对象中的变量tickets,从而满足了我们的要求。
//实现Runnable接口适合多个相同的程序代码访问处理同一资源
TicketRunnable ticketrunnable = new TicketRunnable();
new Thread(ticketrunnable).start();
new Thread(ticketrunnable).start();
new Thread(ticketrunnable).start();
new Thread(ticketrunnable).start();
}
}
而继承继承Thread类,并重载run方法不能达到此目的
如下所示:
public class TicketThread extends Thread {
private int tickets = 100;
public void run(){
while(true){
if(tickets>0){
System.out.println(Thread.currentThread().getName() +
"is saling ticket " + tickets--);
}
}
}
}
public class TicketThreadDemo {
public static void main(String[] args){
//我们希望的是四个线程共售100,我们创建四个线程
//但结果与我们希望的相反,各个线程各售100张票
new TicketThread().start();
new TicketThread().start();
new TicketThread().start();
new TicketThread().start();
// 如果我们象下面这样写的话,只有一个线程在售票,没有实现四个线程并发售票
// TicketThread ticketThread = new TicketThread();
// ticketThread.start();
// ticketThread.start();
// ticketThread.start();
// ticketThread.start();
}
}
3.后台线程
public class DaemonTest {
public static void main(String[] args){
TicketRunnable ticketRunnable = new TicketRunnable();
Thread thread = new Thread(ticketRunnable);
thread.setDaemon(true);//将此线程设置为后台线程,当进程中只有后台线程时,进程就会结束
thread.start();
}
}
4.联合线程
(还没搞懂)
5. 线程同步
在上面的售票程序中,线程可能是不安全的,
比如我们修改一下:
public class ThreadRunnable implements Runnable{
private int tickets = 100;
public void run() {
while(true){
if(tickets > 0){
try{
Thread.sleep(10);//使该线程暂停,
}catch(Exception e){
System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName() +
" is saling ticket " + tickets--);
}
}
}
}
再次测试时,发现可能会打印-1 -2 这样的ticket
所以我们要修改一下,使该程序是线程安全的,
public class TicketSynch implements Runnable{
private int tickets = 100;
String str = new String("");//此对象放在run函数之外
public void run(){
while(true){
synchronized(str){//同步代码块
if(tickets > 0){
try{
Thread.sleep(10);
}
catch(Exception e){
System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()
+" is saling ticket " + tickets--);
}
}
}
}
}
但是 同步以牺牲程序的性能为代价
5. 同步函数
public class SynchMethod implements Runnable{
private int tickets = 100;
public void run(){
while(true){
sale();
}
}
public synchronized void sale(){
if(tickets > 0){
try{
Thread.sleep(10);
}catch(Exception e){
System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()
+ "is saling ticket " + tickets--);
}
}
}
public static void main(String[] args){
//创建了四个线程,每个线程调用了同一各TicketRunnable对象中run方法,
//访问的是同一个对象中的变量tickets,从而满足了我们的要求。
//实现Runnable接口适合多个相同的程序代码访问处理同一资源
SynchMethod synchMethod = new SynchMethod();
new Thread(synchMethod).start();
new Thread(synchMethod).start();
new Thread(synchMethod).start();
new Thread(synchMethod).start();
}
6.代码块和函数间的同步
public class MethodAndBlockSyn implements Runnable{
private int tickets = 100;
String str = new String("");
public void run(){
if(str.equals("method")){
while(true){
sale();
}
}
else{
synchronized(str){//同步代码块
if(tickets > 0){
try{
Thread.sleep(10);
}
catch(Exception e){
System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()
+" is saling ticket " + tickets--);
}
}
}
}
public synchronized void sale(){
if(tickets > 0){
try{
Thread.sleep(10);
}catch(Exception e){
System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()
+ "is saling ticket " + tickets--);
}
}
}
public static void main(String[] args){
MethodAndBlockSyn test = new MethodAndBlockSyn();
new Thread(test).start();// 这个线程调用同步代码块
try{
Thread.sleep(1);//让线程等待100ms 是为了让该线程得到CPU
//避免该线程未得到CPU就将str设置为method,从而使此线程也是调用同步函数
}catch(Exception e)
{
}
test.str = new String("method");
new Thread(test).start();//这个线程调用同步函数
}
7. 线程间通讯
wait: 告诉当前线程放弃监视器并进入睡眠状态,知道有其他线程进入同一监视器并调用notify为止。
notify:唤醒同一对象监视器中调用wait的第一个线程。类似饭馆有一个空位置后通知所有等待就餐顾客中的第一位可以入座的情况
notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的程序先被唤醒并执行。
以上三个方法只能在synchronized方法中调用
public class Record {
private String name = "陈世美";
private String sex = "女";
boolean bFull = false;
public synchronized void put(String name, String sex)
{
if(bFull)
try {
wait();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
this.name = name;
try{
Thread.sleep(10);
}
catch(Exception e){
System.out.println(e.getMessage());
}
this.sex = sex;
bFull = true;
notify();
}
public synchronized void get(){
if(!bFull)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name + "--->" + sex);
bFull = false;
notify();
}
}
public class Productor implements Runnable {
Record record = null;
public Productor(Record record){
this.record = record;
}
public void run(){
int i = 0;
while(true){
if(i==0)
record.put("陈陈陈", "男");
else
record.put("陈世美", "女");
i = (i+1)%2;
}
}
}
public class Consumer implements Runnable {
Record record = null;
public Consumer(Record record){
this.record = record;
}
public void run(){
while(true){
record.get();
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Record record = new Record();
new Thread(new Productor(record)).start();
new Thread(new Consumer(record)).start();
}