一.使用
1.第一种方式
//mythread
public class myClass extends Thread{
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println("run:"+i);
}
}
}
//main
public class helloJava {
public static void main(String[] args) {
myClass th = new myClass();
th.start();
for (int i = 0; i < 20; i++) {
System.out.println("main"+i);
}
}
}
2.第二种方式
public class myClass implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("thread:"+i);
}
}
}
public class helloJava {
public static void main(String[] args){
myClass temp = new myClass();
Thread imp = new Thread(temp);
imp.start();
for (int i = 0; i < 20; i++) {
System.out.println("main:"+i);
}
}
}
3.内存图解
4.thread和Runable的区别
5.匿名内部类实现线程的创建
匿名内部类的作用:
- 把子类继承父类,重写父类方法,创建字类对象一气呵成
- 把实现类实现接口,重写接口方法,创建类对象一气呵成
public class main {
public static void main(String[] args) {
//匿名内部类
//法1
new Thread(){
//重写run方法
@Override
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println("th1:"+i);
}
}
}.start();
//法2
Runnable imp = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("th2:"+i);
}
}
};
new Thread(imp).start();
for (int i = 0; i < 20; i++) {
System.out.println("main:" + i);
}
}
}
二.线程安全
mainTest:
public class main {
public static void main(String[] args) {
threadImp th = new threadImp();
Thread th1 = new Thread(th);
Thread th2 = new Thread(th);
th1.start();
th2.start();
for (int i = 0; i < 3; i++) {
System.out.println("main:" + i);
}
}
}
1.同步代码块
public class threadImp implements Runnable {
private int ticket = 10;
@Override
public void run() {
while (true){
synchronized (this) {
if (ticket > 0) {
System.out.println("ticket:" + ticket);
ticket--;
}
if (ticket <= 0) {
break;
}
}
}
}
}
2.同步方法
同步方法:使用synchronized修饰的方法,就叫同步方法,保证A线程执行该方法的时候,其他线程只能再方法外等待
同步方法的锁对象是this
public class main {
public static void main(String[] args) {
threadImp th = new threadImp();
Thread th1 = new Thread(th);
Thread th2 = new Thread(th);
th1.start();
th2.start();
for (int i = 0; i < 3; i++) {
System.out.println("main:" + i);
}
}
}
静态同步方法:
main:
public class main {
public static void main(String[] args) {
//threadImp th = new threadImp();
Thread th1 = new Thread(new threadImp());
Thread th2 = new Thread(new threadImp());
th1.start();
th2.start();
for (int i = 0; i < 3; i++) {
System.out.println("main:" + i);
}
}
}
thread:
public class threadImp implements Runnable {
private static int ticket = 10;
@Override
public void run() {
fun();
}
public static synchronized void fun(){
while (true){
if (ticket > 0) {
System.out.println("ticket:" + ticket);
ticket--;
}
if (ticket <= 0) {
break;
}
}
}
}
静态方法只能访问静态成员变量;静态成员是类的所有对象中共享的成员,而不是某个对象的成员
3.锁机制
public class threadImp implements Runnable {
private int ticket = 10;
ReentrantLock loc = new ReentrantLock();
@Override
public void run() {
fun();
}
public void fun(){
loc.lock();
while (true){
if (ticket > 0) {
System.out.println("ticket:" + ticket);
ticket--;
}
if (ticket <= 0) {
break;
}
}
loc.unlock();
}
}
main:
public class main {
public static void main(String[] args) {
threadImp th = new threadImp();
Thread th1 = new Thread(th);
Thread th2 = new Thread(th);
th1.start();
th2.start();
for (int i = 0; i < 3; i++) {
System.out.println("main:" + i);
}
}
}
三.等待唤醒机制
1.使用
public class main {
public static boolean count = false;//有无包子的状态
public static void main(String[] args) {
ReentrantLock loc = new ReentrantLock();
Runnable buy = new Runnable() {
@Override
public void run() {
while (true){
synchronized (loc){
System.out.println("消费者");
try {
loc.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费中");
}
}
}
};
Runnable sell = new Runnable() {
@Override
public void run() {
while (true){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (loc){
System.out.println("生产完成");
loc.notify();
}
}
}
};
new Thread(sell).start();
new Thread(buy).start();
}
}
2.生产者消费者模型
(1)第一版:同一个类
package cn.java.test;
/*
*/
import java.util.concurrent.locks.ReentrantLock;
public class main {
public static boolean count = false;//有无包子的状态
static ReentrantLock loc = new ReentrantLock();
public static void main(String[] args) {
Runnable buy = new Runnable() {
@Override
public void run() {
while (true){
synchronized (loc){
if(count == true){
try {
loc.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("正在生产");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count=true;
System.out.println("生产完成");
loc.notify();//随机唤醒一个
}
}
}
};
Runnable sell = new Runnable() {
@Override
public void run() {
while (true){
synchronized (loc){
if(count == false){
try {
loc.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("正在吃");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = false;
System.out.println("吃完了");
loc.notify();
}
}
}
};
new Thread(sell).start();
new Thread(buy).start();
}
}
(2)分文件
测试:
public class main {
public static void main(String[] args) {
obj a = new obj();
sellPerson sell = new sellPerson(a);
buyPerson buy = new buyPerson(a);
new Thread(sell).start();
new Thread(buy).start();
}
}
物品:
public class obj{
boolean flag=false;
}
生产者:
public class sellPerson implements Runnable{
private obj temp;
public sellPerson(obj temp) {
this.temp = temp;
}
@Override
public void run() {
while(true) {
synchronized (temp) {
if (temp.flag == true) {
try {
temp.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("正在生产");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
temp.flag = true;
System.out.println("生产完成");
temp.notify();//随机唤醒一个
}
}
}
}
消费者:
public class buyPerson implements Runnable {
private obj temp;
public buyPerson(obj temp) {
this.temp = temp;
}
@Override
public void run() {
while(true){
synchronized (temp){
synchronized (temp){
if(temp.flag == false){
try {
temp.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("正在吃");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
temp.flag = false;
System.out.println("吃完了");
temp.notify();
}
}
}
}
}
四.线程池使用
public class main {
public static void main(String[] args) {
ExecutorService ex = Executors.newFixedThreadPool(3);
ex.submit(new threadImp());
ex.submit(new threadImp());
ex.submit(new threadImp());
ex.shutdown();//不建议执行,执行完就结束了
}
}
public class threadImp implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
五.lambda表达式
lambda是java8的一个新特性,格式由三部分组成,省去了面向对象的条条框框
- 一些参数
- 一个箭头
- 一段代码
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑
格式:(参数类型 参数名称)->(代码语句)
():接口中抽象方法的参数列表,没有参数,就空着,有参数就写出参数,多个参数用逗号隔离
->:传递的意思,把参数传递给方法体
{}:重写接口的抽象方法的方法体
lambda的重要参数:
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
(1)无参无返回
public interface Cook {
public abstract void makeCook();
}
public class main {
public static void main(String[] args) {
//法1
fun(new Cook(){
@Override
public void makeCook() {
System.out.println("无lambda");
}
});
//法2
fun(()->{
System.out.println("lambda");
});
}
public static void fun(Cook cook){
cook.makeCook();
}
}
(2)参数和返回值
public class person {
private int age;
private String name;
public person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class main {
public static void main(String[] args) {
person[] arr = {
new person(18,"张三"),
new person(19,"李四"),
new person(17,"王五")
};
/*
Arrays.sort(arr, new Comparator<person>() {
@Override
public int compare(person o1, person o2) {
return o1.getAge()-o2.getAge();
}
});
for(person i:arr){
System.out.println(i.getName()+i.getAge());
}
*/
Arrays.sort(arr,(person o1,person o2)->{
return o1.getAge()-o2.getAge();
});
for(person i:arr){
System.out.println(i.getName()+i.getAge());
}
}
}
例2:
public interface Cook {
public abstract int makeCook(int a,int b);
}
public class main {
public static void main(String[] args) {
//调用cal方法,方法的参数是一个接口,可以采用匿名内部类
cal(2, 3, new Cook() {
@Override
public int makeCook(int a, int b) {
return a+b;
}
});
//lambda表达式
cal(4,5,(int a,int b)->{
return a+b;
});
}
/*
定义一个方法:传递两个整数和一个接口
计算两个整数的和
*/
public static void cal(int a,int b,Cook cook){
int c = cook.makeCook(a,b);
System.out.println(c);
}
}
(3)参数的省略
可以省略:
1.括号内参数的类型可以省略
2.如果小括号内,有且仅有一个参,小括号可以省略
3.如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略({},return,;)
注意:要省略,必须三个一起省略
public class main {
public static void main(String[] args) {
//3.例子
new Thread(()->{
System.out.println("3:省略前");
}).start();
new Thread(()-> System.out.println("3:省略后")).start();
// 1 和 3
person[] arr = {
new person(18,"张三"),
new person(19,"李四"),
new person(17,"王五")
};
Arrays.sort(arr,(o1, o2)->o1.getAge()-o2.getAge());
for(person i:arr){
System.out.println(i.getName()+i.getAge());
}
}
}
注意:
lambda使用方法非常简洁,完全没有面向对象复杂的束缚,但是是羊奶粉的时候必须要注意几点 1.使用lambda必须有抽象方法,而且抽象方法必须有且仅有一个抽象方法 2.使用lambda必须有上下文推断 即:方法的参数或者局部变量类型必须为Lambda对应的接口类型,才能使用lambda作为给实例的接口 备注:有且仅有一个抽象方法的接口,成为“函数式接口”