1.多线程
概述:线程是程序执行的一条路径, 一个进程中可以包含多条线程,多线程并发执行可以提高程序的效率, 可以同时完成多项工作。
1.1并行和并发
- 并行:两个任务同时运行,即甲在运行的同时,乙也在运行(需要多核CPU)
- 并发:两个任务都请求运行,而处理器只接受一个任务,就把这两个任务安排轮流进行,由于时间间隔短,两个任务感觉在同时运行。
1.2多线程的几种实现方式
1.2.1继承Thread,重写run方法
public class Demo_Thread {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
}
}
class MyThread extends Thread{
public void run(){
for(int i=0;i<10000;i++){
System.out.println("hhhhhhhhhh");
}
}
}
匿名内部类实现:
public class Demo_Thread {
public static void main(String[] args) {
new Thread(){
public void run(){
for(int i=0;i<10000;i++){
System.out.println("匿名内部类hhhhhhhhhh");
}
}
}.start();
}
}
1.2.2实现Runnable接口,重写run方法
通过实现Runnable接口,实现run方法,接口的实现类的实例作为Thread的target作为参数传入带参的Thread构造函数,通过调用start()方法启动线程
public class Demo_Runnable {
public static void main(String[] args) {
MyRunnable mr=new MyRunnable();
Thread t=new Thread(mr);
t.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<10000;i++){
System.out.println("hhhhhhhhhh");
}
}
}
②匿名内部类实现:
public class Demo_Thread {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10000;i++){
System.out.println("匿名内部类hhhhhhhhhh");
}
}
}).start();
}
}
两种方式的区别:
- 继承Thread:由于子类重写了Thread中的run(),当调用start()时,直接找子类的run()方法。
- 实现Runnable():构造函数中传入了Runnable的引用,成员变量记住了他,start()调用run()方法时内部判断成员变量Runnable的引用是否为空,不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法
1.3获取线程名字和设置名字
- 通过getName()方法获取名字
- 通过构造参数或者setName()方法设置名字
//构造方法
new Thread("程序汪"){
public void run(){
//this.setName("程序汪");
System.out.println(this.getName()+"....hhhhhh");
}
}.start();
//setName()方法
new Thread(){
public void run(){
this.setName("程序汪");
System.out.println(this.getName()+"....hhhhhh");
}
}.start();
1.4获取当前线程的对象
概述:Thread.currentThread(), 主线程也可以获取。为Runnable()提供了方便
new Thread(new Runnable() {
public void run() {
Thread.currentThread().setName("程序员");
System.out.println(Thread.currentThread().getName()+"...hhhh");
}
}).start();
1.5.1休眠线程
sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
for(int i=5;i>0;i--){
Thread.sleep(1000);
System.out.println("倒计时"+i+"秒");
}
1.5.2守护线程
概述:setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出。
Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 2; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaa");
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
System.out.println(getName() + "...bb");
}
}
};
t2.setDaemon(true); //设置为守护线程
t1.start();
t2.start();
1.5.3加入进程
join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续
join(int), 可以等待指定的毫秒之后继续
final Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaa");
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
if(i==2){
try {
t1.join(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(getName() + "...bb");
}
}
};
t1.start();
t2.start();
1.5.4礼让线程
yield让出cpu
1.5.5设置 线程优先级
概述:setPriority()设置线程的优先级,效果不太明显
例如:
Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaa");
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(getName() + "...bbbbbbbbbbbbbbbbb");
}
}
};
t1.setPriority(10);
t2.setPriority(1);
t1.start();
运行截图未给出,自己可尝试运行看结果。
1.6.1同步代码块
概述: 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步。如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
如果同步代码块就有可能出现以下情况。
Demo demo=new Demo();
new Thread(){
public void run(){
while(true){
demo.print1();
}
}
}.start();
new Thread(){
public void run(){
while(true){
demo.print2();
}
}
}.start();
class Demo{
public void print1(){
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.println();
}
public void print2(){
System.out.print("撸");
System.out.print("代");
System.out.print("码");
System.out.println();
}
}
同步代码块以后:
主方法不变
注:锁对象为任意对象,但是被锁的代码需要保证是同一把锁,不能使用匿名对象。
class Demo{
Demo1 demo1=new Demo1();
public void print1(){
synchronized (demo1) {
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.println();
}
}
public void print2(){
synchronized (demo1) {
System.out.print("撸");
System.out.print("代");
System.out.print("码");
System.out.println();
}
}
}
class Demo1{
}
运行结果不会再有未完成当前操作就切换CPU的操作。
1.6.2同步方法
使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
非静态同步函数的锁是:this
静态的同步函数的锁是:字节码对象
class Demo{
public synchronized void print1(){
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.println();
}
public void print2(){
synchronized (this) {
System.out.print("撸");
System.out.print("代");
System.out.print("码");
System.out.println();
}
}
}