【Java编程】Java多线程的实现
2017-08-14 22:14
281 查看
多线程
程序:是一个指令的集合。
进程:正在执行中的程序,是一个静态的概念。
线程:是进程中的一个单一的连续控制流程,线程又本称为轻量级进程。
一个进程可拥有多个并行的线程,一个进程中的线程共享相同的内存单元,内存地址空间,可以访问相同的变量和对象,而且他们从同一堆中分配对象,通信,数据交换,同步操作。
由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便,而且信息传递速度也更快。
java多线程实现的方法有两种。
第一种:
继承Thread类,重写run方法,创建对象,调用start方法启动多线程。
第二种:
实现Runnable接口,重写run方法,创建对象,调用start方法启动多线程。
实现Runnable接口的类不能直接调用start方法,需要创建一个Thread对象,然后把对象传进去,在调用start方法。
继承Thread类开启多线程:
注意一点,在开启多线程的时候需要调用start,不能直接调用run方法,因为在开启多线程前,需要一些准备工作,这些工作就需要start来做,start在做完这些准备工作后在去调用run方法。
实现Runnable接口开启多线程
实现Runnable接口不能直接调用start方法,因为start方法属于Thread的,所以需要new一个Thread然后把对象传进去,通过Thread调用start方法
常见的方法:
sleep 睡眠 让线程睡眠一定的时间。它有两种睡眠时间,一种是毫秒,一种是纳秒
join插队 任何一个线程在调用join后,那么他就有优先执行的权利,其他的线程都要等到调用join方法的线程执行完毕,才可以执行。
通过上面的代码可以看出run方法在执行的是后遇到了sleep所以睡眠了,这是main继续执行完毕,但是在调用join后main方法就只有等到run方法执行完毕才能继续执行
yield让步 正在执行的线程给给另一个线程让一下,然后继续执行,只是让了一步。
调用方法:
wait 等待 然正在执行的线程进入等待,需要被唤醒,没有唤醒将会一直等待下去,不会自己醒来。
使用方法:
finally 唤醒等待的线程
finallyAll唤醒所有等待的线程。
下面给一个多线程使用的例子:
现有100张火车票,让5个人去卖票,直到卖完为止。
代码如下:
/**
* 多线程(卖火车票)
*
* @author FengYuan
*
*/
public class Test implements Runnable {
int ticket = 100; // 100张火车票
/*
* 实现Runnable接口然后重写run方法 因为火车票共享所以必须用Runnable
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// 获取当前线程的名称
String name = Thread.currentThread().getName();
if (ticket > 0) {
System.out.println(name + "卖出的第" + ticket + "张票");
ticket--; // 每卖出一张减1
} else {
System.out.println("票买完了");
}
}
public static void main(String[] args) {
Test t = new Test();
for (int i = 0; i <= 22; i++) {
new Thread(t, "1号").start();
new Thread(t, "2号").start();
new Thread(t, "3号").start();
new Thread(t, "4号").start();
new Thread(t, "5号").start();
}
}
}
从上面的代码运行后我们可以看出卖的票有好多重复的,这就好比多个人同时买到的一张火车票,这样的话是不是存在很大的问题,所以有给出了一个方法,可以避免这种情况的发生。
synchronize线程锁,给线程加一把锁,在看效果。
代码如下:
/**
* 多线程(卖火车票)
*
* @author FengYuan
*
*/
public class Test implements Runnable {
int ticket = 100; // 100张火车票
/*
* 实现Runnable接口然后重写run方法 因为火车票共享所以必须用Runnable
*
* @see java.lang.Runnable#run()
*/
@Override
public synchronized void run() {
// 获取当前线程的名称
String name = Thread.currentThread().getName();
if (ticket > 0) {
System.out.println(name + "卖出的第" + ticket + "张票");
ticket--; // 每卖出一张减1
} else {
System.out.println("票买完了");
}
}
public static void main(String[] args) {
Test t = new Test();
for (int i = 0; i <= 22; i++) {
new Thread(t, "1号").start();
new Thread(t, "2号").start();
new Thread(t, "3号").start();
new Thread(t, "4号").start();
new Thread(t, "5号").start();
}
}
}
加锁之后的代码我们再次运行就会发现,票没有重复的了。
这是因为在线程没有上锁的情况下,就会有多个线程进同时进入方法,这样就会造成重复,而枷锁之后,线程每次只能执行一个,一个线程执行完后才能进入下一个线程。
程序:是一个指令的集合。
进程:正在执行中的程序,是一个静态的概念。
线程:是进程中的一个单一的连续控制流程,线程又本称为轻量级进程。
一个进程可拥有多个并行的线程,一个进程中的线程共享相同的内存单元,内存地址空间,可以访问相同的变量和对象,而且他们从同一堆中分配对象,通信,数据交换,同步操作。
由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便,而且信息传递速度也更快。
java多线程实现的方法有两种。
第一种:
继承Thread类,重写run方法,创建对象,调用start方法启动多线程。
第二种:
实现Runnable接口,重写run方法,创建对象,调用start方法启动多线程。
实现Runnable接口的类不能直接调用start方法,需要创建一个Thread对象,然后把对象传进去,在调用start方法。
继承Thread类开启多线程:
注意一点,在开启多线程的时候需要调用start,不能直接调用run方法,因为在开启多线程前,需要一些准备工作,这些工作就需要start来做,start在做完这些准备工作后在去调用run方法。
/** * 使用多线程打印到1-100 * * @author FengYuan * */ public class Test extends Thread { /* * 继承Thread类然后重写run方法 * * @see java.lang.Thread#run() */ @Override public void run() { for (int i = 0; i <= 100; i++) { System.out.println("线程:" + i); } } public static void main(String[] args) { Test t = new Test(); t.start();// 注意多线程的开启需要调用start,不能直接调用run。 for (int i = 0; i <= 100; i++) { System.out.println("main方法::" + i); } } }
实现Runnable接口开启多线程
实现Runnable接口不能直接调用start方法,因为start方法属于Thread的,所以需要new一个Thread然后把对象传进去,通过Thread调用start方法
/** * 使用多线程打印到1-100 * * @author FengYuan * */ public class Test implements Runnable { /* * 实现Runnable接口然后重写run方法 * * @see java.lang.Runnable#run() */ @Override public void run() { for (int i = 0; i <= 100; i++) { System.out.println("线程:" + i); } } public static void main(String[] args) { Test t = new Test(); new Thread(t).start(); // 注意实现Runnable接口对象不可以直接调用start。 for (int i = 0; i <= 100; i++) { System.out.println("main方法::" + i); } } }
常见的方法:
sleep 睡眠 让线程睡眠一定的时间。它有两种睡眠时间,一种是毫秒,一种是纳秒
/** * 多线程 * * @author FengYuan * * 4000 / public class Test extends Thread { /* * 继承Thread类然后重写run方法 * * @see java.lang.Runnable#run() */ @Override public void run() { try { sleep(1000); // 让线程睡眠1秒,1000毫秒等于一秒 } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i <= 100; i++) { try { sleep(0, 1000); // 每打印一次让线程睡眠1000纳秒,当然速度太快,看不出效果。 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程:" + i); } } public static void main(String[] args) { Test t = new Test(); t.start(); // 注意实现Runnable接口对象不可以直接调用start。 for (int i = 0; i <= 100; i++) { System.out.println("main方法::" + i); } } }
join插队 任何一个线程在调用join后,那么他就有优先执行的权利,其他的线程都要等到调用join方法的线程执行完毕,才可以执行。
通过上面的代码可以看出run方法在执行的是后遇到了sleep所以睡眠了,这是main继续执行完毕,但是在调用join后main方法就只有等到run方法执行完毕才能继续执行
/** * 多线程 * * @author FengYuan * */ public class Test extends Thread { /* * 继承Thread类然后重写run方法 * * @see java.lang.Runnable#run() */ @Override public void run() { try { sleep(1000); // 让线程睡眠1秒,1000毫秒等于一秒 } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i <= 100; i++) { try { sleep(0, 1000); // 每打印一次让线程睡眠1000纳秒,当然速度太快,看不出效果。 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程:" + i); } } public static void main(String[] args) { Test t = new Test(); t.start(); // 注意实现Runnable接口对象不可以直接调用start。 try { t.join(); // 调用join } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i <= 100; i++) { System.out.println("main方法::" + i); } } }
yield让步 正在执行的线程给给另一个线程让一下,然后继续执行,只是让了一步。
调用方法:
Thread.yield();
wait 等待 然正在执行的线程进入等待,需要被唤醒,没有唤醒将会一直等待下去,不会自己醒来。
使用方法:
t.wait();
finally 唤醒等待的线程
finallyAll唤醒所有等待的线程。
t.finally(); // 唤醒一个等待的线程
t.finallyAll(); // 唤醒所有等待的线程
下面给一个多线程使用的例子:
现有100张火车票,让5个人去卖票,直到卖完为止。
代码如下:
/**
* 多线程(卖火车票)
*
* @author FengYuan
*
*/
public class Test implements Runnable {
int ticket = 100; // 100张火车票
/*
* 实现Runnable接口然后重写run方法 因为火车票共享所以必须用Runnable
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// 获取当前线程的名称
String name = Thread.currentThread().getName();
if (ticket > 0) {
System.out.println(name + "卖出的第" + ticket + "张票");
ticket--; // 每卖出一张减1
} else {
System.out.println("票买完了");
}
}
public static void main(String[] args) {
Test t = new Test();
for (int i = 0; i <= 22; i++) {
new Thread(t, "1号").start();
new Thread(t, "2号").start();
new Thread(t, "3号").start();
new Thread(t, "4号").start();
new Thread(t, "5号").start();
}
}
}
从上面的代码运行后我们可以看出卖的票有好多重复的,这就好比多个人同时买到的一张火车票,这样的话是不是存在很大的问题,所以有给出了一个方法,可以避免这种情况的发生。
synchronize线程锁,给线程加一把锁,在看效果。
代码如下:
/**
* 多线程(卖火车票)
*
* @author FengYuan
*
*/
public class Test implements Runnable {
int ticket = 100; // 100张火车票
/*
* 实现Runnable接口然后重写run方法 因为火车票共享所以必须用Runnable
*
* @see java.lang.Runnable#run()
*/
@Override
public synchronized void run() {
// 获取当前线程的名称
String name = Thread.currentThread().getName();
if (ticket > 0) {
System.out.println(name + "卖出的第" + ticket + "张票");
ticket--; // 每卖出一张减1
} else {
System.out.println("票买完了");
}
}
public static void main(String[] args) {
Test t = new Test();
for (int i = 0; i <= 22; i++) {
new Thread(t, "1号").start();
new Thread(t, "2号").start();
new Thread(t, "3号").start();
new Thread(t, "4号").start();
new Thread(t, "5号").start();
}
}
}
加锁之后的代码我们再次运行就会发现,票没有重复的了。
这是因为在线程没有上锁的情况下,就会有多个线程进同时进入方法,这样就会造成重复,而枷锁之后,线程每次只能执行一个,一个线程执行完后才能进入下一个线程。
相关文章推荐
- 【Java并发编程】之六:Runnable和Thread实现多线程的区别(含代码)
- 10 Java 多线程编程环境中单例模式的实现
- java使用多线程编程,实现socket服务器客户端交互
- Java多线程编程环境中单例模式的实现
- Java的多线程编程模型5--从AtomicInteger开始(自增长实现)
- 【Java并发编程】之六:Runnable和Thread实现多线程的区别(含代码)
- java网络编程:RandomAccessFile, URLConnection和多线程机制实现了Http下载
- java 多线程编程三种实现方式
- 【Java并发编程】之六:Runnable和Thread实现多线程的区别(含代码)
- java多线程以及java网络编程实现简单的聊天系统
- Java Socket编程之用多线程实现多人聊天工具
- 【java编程】IO特殊类之RandomAccessFile实现多线程文件下载
- 【Java并发编程】之六:Runnable和Thread实现多线程的区别(含代码)
- Java基础知识强化之网络编程笔记05:UDP之多线程实现聊天室案例
- Java多线程编程环境中单例模式的实现 (内部类实现多线程环境中的单例模式)
- 【Java并发编程】Runnable和Thread实现多线程的区别
- Java 多线程编程环境中单例模式的实现
- 【Java并发编程】之六:Runnable和Thread实现多线程的区别(含代码)
- Java 技术: 使您轻松地进行多线程应用程序编程——Consumer 类可以简化生产者-消费者行为的实现
- Java多线程编程的实现