Java多线程
关键技能与概念
1.理解多线程的基础知识
多任务有两种不同的类型:
(1)基于进程的多任务
(2)基于线程的多任务
这两个有什么区别呢?
进程的本质上是指正在执行的程序,所以进程的多任务是指计算机同时运行两个或多个程序功能。打开任务管理器,你会发现有很多程序在运行
你会发现有很多任务在同时运行。这属于基于进程的多任务。
而基于线程的多任务环境中,线程是最小的可调度代码单元。
这意味着,程序一次可以执行多项任务,需要多核CPU处理。
对于线程呢?
也就是程序运行的路线,它将如何执行程序,当前程序执行完后下一个运行执行啥程序?线程有两种装态,一是运行状态(running),二是就绪状态,一旦得到CPU的时间就开始执行。
并行与并发
其实这两个慨念很简单,并行则是多个线程在同一时间运行,而并发是多个线程轮流执行,比如循环排队。
Thread类和Runnable接口
首先我们来探索 Thread类的几个常用方法。
方法 | 含义 |
---|---|
final String getName() | 获取线程名 |
final int getPriority() | 获取线程优先级 |
final boolean isAlive() | 判断该线程是否在运行 |
final void join() | 等待线程终止 |
void run() | 线程的进入点 |
static void sleep(long milliseconds) | 按照指定的时间挂起线程以毫秒为单位 |
void start() | 通过调用线程的run方法启动线程 |
1.实现Runnable接口实现的多线程
package threadTest;
// 通过实例化一个Thread类型对象可以创建一个线程。
// Thread类封装可运行对象
// 主要步骤为 1. 实现 Runnable 接口 2. 扩展 Tread 类。
/*
在 Runnable 接口抽象了一个可执行代码单元,可以在实现Runnable接口的任何对象上构造线程。
但实际上
Runnable 类中只有一个方法 :
public void run();
是不很好奇 为什么只有一个方法,其实这只是写多线程的一个规范。
在创建一个实现Runnable接口后再实例化一个Thread 类型的对象,在Thread类中有好几个构造方法如下:
Thread (Runnable ThreadObject)
再调用 start() 方法运行线程
*/
// 我想。有没有小伙伴根据以上文字的描叙,自己写一段代码
// 可以的话 ,欢迎在评论区留言。
public class MyThread implements Runnable{
String ThreadName;
public MyThread (String ThreadName){
this.ThreadName = ThreadName;
}
public void run(){
System.out.println(ThreadName +"staring");
try {
for (int count = 0; count < 10; count++) {
Thread.sleep(100);
System.out.println("In" + ThreadName + ", count is " + count);
}
}
catch (InterruptedException exc){
System.out.println(ThreadName+"interrupted.");
}
System.out.println(ThreadName +" terminating.");
}
}
class UseThreads {
public static void main(String [] args){
System.out.println("Main threading staring ");
// First ,construct a MyThread object .
MyThread mt = new MyThread("You love me"); // 创建一个运行对象
Thread newThread = new Thread(mt); // 在该对象上构造一个线程。
newThread.start();
for(int i=0;i<10;i++) {
System.out.println("I love you" + " " + i);
try {
Thread.sleep(200);
} catch (InterruptedException exc) {
System.out.println("Main thread interrupted");
}
}
System.out.println(" Main thread ending");
q
}
}
/* /输出结果如下:
Main threading staring
You love me staring
I love you 0
InYou love me , count is 0
InYou love me , count is 1
I love you 1
InYou love me , count is 2
I love you 2
InYou love me , count is 3
InYou love me , count is 4
I love you 3
InYou love me , count is 5
InYou love me , count is 6
I love you 4
InYou love me , count is 7
InYou love me , count is 8
I love you 5
InYou love me , count is 9
You love me terminating.
I love you 6
I love you 7
I love you 8
I love you 9
Main thread ending
Process finished with exit code 0
*/
// 可以看的出来 Love you 与 Love me 并不是一次性输出而是间断性的输出。
// 这就是我在前面说的并发
以上代码还可以改写为如下代码,希望小伙伴能找到不同之处,并分析为什要这样写,有什么好处。
class MyThread implements Runnable{
Thread thread ; // 线程的引用
// Construct a new thread using this Runnable and give
MyThread(String name){
thread = new Thread(this,name);
}
public static MyThread createAndStart(String name){
MyThread myThread = new MyThread(name);
myThread.thread.start(); // 开始执行线程
return myThread;
}
public void run(){
System.out.println(thread.getName()+"staring");
try{
for(int count =0;count<10;count++){
Thread.sleep(400);
System.out.println("I Love you "+thread.getName() + "count is :" +count);
}
}
catch(InterruptedException exc){
System.out.println("Thread is interrupted"+thread.getName());
}
System.out.println(thread.getName()+" terminating.");
}
}
class ThreadVariations{
public static void main(String [] args){
System.out.println("Main thread starting");
// Create and start a thread;
MyThread f = MyThread.createAndStart("You love me");
for(int i =0;i<50;i++){
System.out.println(f.thread.getName());
try{
Thread.sleep(100);
}
catch(InterruptedException exc){
System.out.println("Main thread interrupted");
}
}
System.out.println("Main Thread ending");
}
}
2.继承Thread类的线程
注意,继承Thread类重写的是Thread 类中的Run反法,相当于简接的实现Runnable中的run犯法,而1.中则是直接实现run方法。
一个是重写。一个是实现接口。两者那种方法更好
欢迎在评论区留言!
public class ExtendThread {
public static void main(String [] args){
System.out.println("Main thread starting");
MyThread01 fy = new MyThread01("You Love me ");
fy.start();
for(int i =0;i<50;i++){
System.out.println(fy.getName());
try{
Thread.sleep(500);
}
catch(InterruptedException exc){
System.out.println("Main Thread ");
}
}
System.out.println("Thread is ending");
}
}
class MyThread01 extends Thread{
MyThread01(String name){
super(name); // name thread.
} // 用super调用父类的构造方法Thread(String threadName)
// 添加 run() 方法
public void run() {
System.out.println(getName() + "Thread staring");
try{
for (int count = 0; count < 10; count++) {
Thread.sleep(100);
System.out.println(getName() + "I Love you" + " count is" + count);
}
}
catch(InterruptedException exc){
System.out.println(getName() + "interrupted.");
}
System.out.println(getName()+"线程结束");
}
}
1.3创建多个线程
实际上创建多个线程,无非就是多new几个对象,当然也可以多写几个不同的线程,用于完成不同的功能。但是重run方法的基本格式是固定的必须要有try catch 语句。
import java.util.Scanner;
public class ManyThread implements Runnable {
Thread thread ;
// Construct a new thread .
ManyThread (String name){
thread = new Thread(this,name);
}
// a factory method that creates and starts a thread
public static ManyThread createAndStart (String name ){
ManyThread manythread = new ManyThread("I Love you");
manythread.thread.start(); // start the thread
return manythread;
}
public void run(){
System.out.println(thread.getName() + " Starting .");
try {
for(int i =0 ; i<10;i++){
Thread.sleep(400);
System.out.println(" " + thread.getName()+",count is "+ i);
}
}catch(InterruptedException exc ){
System.out.println(thread.getName()+"Interruption");
}
}
}
class MoreThread{
public static void main(String [] args){
Scanner input = new Scanner(System.in);
int n = input.nextInt();
System.out.println("Main Thread staring ");
ManyThread m1 = ManyThread.createAndStart("我爱你");
ManyThread m2 = ManyThread.createAndStart("你爱我");
ManyThread m3 = ManyThread.createAndStart("如果我们两个互不相爱");
for(int i =0 ;i<n;i++){
System.out.print(".");
try{
Thread.sleep(100);
if(m1.thread.isAlive())
System.out.println("线程没有结束");
}
catch(InterruptedException exc){
System.out.println("Main Thread Interruption");
}
}
System.out.println("Main Thread ending");
}
}
1.4确认线程如何结束
其实这个很简单,可以使用 Thread提供的方法
final boolean isAlive()
//使用举例
// if(m1.thread.isAlive())
// System.out.println("线程没有结束");
// 如果线程没有结束,该方法反回 ture 如果结束反回 false。
但在API 文档中的方法为
// public final native boolean isAlive();
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return {@code true} if this thread is alive;
* {@code false} otherwise.
*/
/*
此时的我,产生了疑问,单凭这简单的一句是则么做到的?
我发现在方法前有一个
@Contract(pure = ture)
这是什莫意思呢。
*/
1.5线程的优先级
总体来说就是CPU给一条线程分配的时间有多少,优先级高的分配的时间就多,而优先级低的分配时间就少。注意:
除了优先级外,,还有其它因素对分配多少时间给线程的CPU时间
如 : 一个高优先级的线程正在等待某一资源的输入(可能是键盘的输入),这样它就会被堵塞,而运行优先·级较低的线程。
这说明了,优先级高的线程不一定先执行,当然还有其它因素。
如何设置线程的优先级?
调用Thread类中的setPriority()方法来修改线程的优先级:
final void setPriority(int level)
其中这个 level 的值必须在MIN_PRIORITY和MAX_PRIORITY的范围内,值一般为1~10。如何看线程默认的优先级呢?这就要用到
getPriority方法。
final int getPriority()
这些方法都有一些特性都是用final关键字修饰,说明sun公司的那帮人不想让人更改它们已经写好的方法,你只管用就行。
列题
public class Priority implements Runnable {
int count ;
Thread thread ;
static boolean stop = false;
static String currentName; // 现在流通的名字
// Construct a new Thread
Priority (String name){
thread = new Thread(name);
count = 0;
currentName = name;
}
// Entry point of thread .
public void run(){
System.out.println(thread.getName()+"staring");
do {
count++;
if(currentName.compareTo(thread.getName())!=0){
currentName = thread.getName();
System.out.println(" In "+currentName);
}
}while(stop ==false&&count <1000000 );
stop = true;
System.out.println("/n"+thread.getName()+"terminating");
}
}
class PriorityDemo{
public static void main(String [] args){
Priority m1 = new Priority("High Priority");
Priority m2 = new Priority("Low Priority");
Priority m3 = new Priority("normal Priority #1");
Priority m4 = new Priority("normal Priority #2");
Priority m5 = new Priority ("normal Priority #3");
// set the priority
// 线程的基本流程就是new 完对象就开起线程。
// start the thread
m1.thread.start();
m2.thread.start();
m3.thread.start();
m4.thread.start();
m5.thread.start();
try{
m1.thread.join();
m2.thread.join();
m3.thread.join();
m4.thread.join();
m5.thread.join();
}catch(InterruptedException exc){
System.out.println("Main thread interrupted");
}
System.out.println("\nHigh priority thread counted to"+m1.count);
System.out.println("\nLow priority thread counted to"+m2.count);
System.out.println("\nNormal priority thread counted to"+m3.count);
System.out.println("\nNormal priority thread counted to"+m4.count);
System.out.println("\nNormal priority thread counted to"+m5.count);
}
}
/*
public int compareTo(String anotherString) {
byte v1[] = value;
byte v2[] = anotherString.value;
byte coder = coder();
if (coder == anotherString.coder()) {
return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
: StringUTF16.compareTo(v1, v2);
}
return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
: StringUTF16.compareToLatin1(v1, v2);
}
*/
v2[] = anotherString.value;
byte coder = coder();
if (coder == anotherString.coder()) {
return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
: StringUTF16.compareTo(v1, v2);
}
return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
: StringUTF16.compareToLatin1(v1, v2);
}
*/
以上线程的基础操作。在接下来的几天我会跟新同步,线程的通信。