最近都在学习java,以下是学习笔记。
1 线程
1.1基本线程处理
1)throw与throws的区别
前者用于抛出单个异常,并且该异常知道如何处理,通常是放在catch子句块中,当然也可以在任何想抛出异常的地方。后者可以抛出单个或多个异常,不知道如何处理,通常是放在函数定义后。如下代码片段。
2)join作用
参加,也要别人同意啊。所以,这个函数就是在保证其他线程执行完后,才创建线程。如下,循环创建多个线程,每个线程都是在前面一个线程完成执行后才创建的。
for(int i = 0;i < 5;i ++){
new TestThread().join();
}
3)setPriority设置优先级
可以用来设置线程优先级,优先级高的会使得其执行频率增加。
对于每个操作系统,所规定的线程优先级级数不一致。JDK规定了十个级数。一般使用Thread.MAX_PRORITY、Thread.NORMAL_PRORITY、Thread.MIN_PRORITY三个级数,就可以避免在不同操作系统出现的此类问题。
4)deamon设置为后台
public final void setDaemon (boolean isDaemon)
可以用来设置为后台进程。
某线程A为非后台进程,若使用该函数创建了后台进程B,那么当A终止执行时,后台进程B也会终止执行,即使B仍未执行完代码。
5)join进阶作用
线程A在等待另一个线程B执行完之前,若B自己调用interrupt终止执行,则A马上继续执行join后面的代码。
Join也能传入一个时间参数,该参数表示在规定时间到达时,不管B是否执行完,A均继续执行join后面的代码。
6)runable的作用
Runable使得对象在继承了其他类的情况下,实现线程方法,间接实现多重继承。
Runable只有run方法,当要实现除run方法以外的方法时,可以通过Thread.currentThread()来获得线程对象。如下
使用内部类将线程方法封装起来更加清晰,这里不使用runable。
如下。
1.2进阶线程处理
1)timer.schedule
小贴士
Timer.schedule
void schedule(TimerTask task, long delay)
Schedule a task for single execution after a specified delay.
一般用在运行一个delay的任务,跟thread.sleep差不多。
2)synchronize使用
Static synchronize修饰的方法用于对整个类下所有实例化的对象调用到该方法时均需要同步处理。
Synchronize修饰的方法用于对类下每个实例化的对象在调用到该方法时需要同步处理,也即若A、B两个对象都属于同一个类,A、B两对象在访问到同一个synchronize修饰的类方法时,互不干扰。只有在A这个类第二次访问到A这个方法或是B这个类第二次访问到B这个方法,才有同步处理。
小贴士
以下摘自http://blog.csdn.net/virgoboy2004/article/details/7585182,谢谢作者。
【问题描述】关于Java中synchronized 用在实例方法和对象方法上面的区别
【问题分析】大家都知道,在Java中,synchronized 是用来表示同步的,我们可以synchronized 来修饰一个方法(实例方法和类方法---注:不知道这样叫准确不准确,大家理解我的意识就行了)。也可以synchronized 来修饰方法里面的一个语句块。
修饰实例方法:
[java] view plaincopy
1. public synchronized void x() throws InterruptedException
2. {
3. for (int i = 0; i < 10; i++)
4. {
5. Thread.sleep(1000);
6. System.out.println("x.......................");
7. }
8. }
修饰类方法(static 方法):
[java] view plaincopy
1. public static synchronized void staticX() throws InterruptedException
2. {
3. for (int i = 0; i < 10; i++)
4. {
5. Thread.sleep(1000);
6. System.out.println("staticX.......................");
7. }
8. }
修饰方法里面语句块:
[java] view plaincopy
1. public static void staticX() throws InterruptedException
2. {
3. synchronized (locks)
4. {
5. for (int i = 0; i < 10; i++)
6. {
7. Thread.sleep(1000);
8. System.out.println("staticX.......................");
9. }
10. }
11. }
注意:这里不能用synchronized修饰方法外面的语句块(我把他叫做类语句块),虽然我们可以在方法外面定义语句块,这样做会遇到编译错误,这里涉及到了Java里面的对象初始化的部分知识。大概的原因就是synchronized锁住的是对象,当初始化对象的时候,JVM在对象初始化完成之前会调用方法外面的语句块,这个时候对象还不存在,所以就不存在锁了。
那么,在static方法和非static方法前面加synchronized到底有什么不同呢?
大家都知道,static的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对象),那么static获取到的锁,就是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。而非static方法获取到的锁,就是当前调用这个方法的对象的锁了。所以,他们之间不会产生互斥。
看代码:
[java] view plaincopy
1. package com.jack.zhang.chapter9.classlock;
2.
3. /**
4. * @author Jack Zhang
5. * @version vb1.0
6. * @Email virgoboy2004@163.com
7. * @Date 2012-5-20
8. */
9. public class Test
10. {
11. public static synchronized void staticX() throws InterruptedException
12. {
13. for (int i = 0; i < 10; i++)
14. {
15. Thread.sleep(1000);
16. System.out.println("staticX.......................");
17. }
18. }
19.
20. public synchronized void x() throws InterruptedException
21. {
22. for (int i = 0; i < 10; i++)
23. {
24. Thread.sleep(1000);
25. System.out.println("x.......................");
26. }
27. }
28.
29. public static void main(String[] args)
30. {
31. final Test test1 = new Test();
32. Thread thread = new Thread(new Runnable()
33. {
34. public void run()
35. {
36. try
37. {
38. test1.x();
39. }
40. catch (InterruptedException e)
41. {
42. // TODO Auto-generated catch block
43. e.printStackTrace();
44. }
45. }
46. }, "a");
47.
48. Thread thread1 = new Thread(new Runnable()
49. {
50. public void run()
51. {
52. try
53. {
54. Test.staticX();
55. }
56. catch (InterruptedException e)
57. {
58. // TODO Auto-generated catch block
59. e.printStackTrace();
60. }
61. }
62. }, "b");
63.
64. thread1.start();
65. thread.start();
66. }
67. }
运行结果是:
[java] view plaincopy
1. staticX.......................
2. x.......................
3. x.......................
4. staticX.......................
5. staticX.......................
6. x.......................
7. x.......................
8. staticX.......................
9. x.......................
10. staticX.......................
11. staticX.......................
12. x.......................
13. x.......................
14. staticX.......................
15. x.......................
16. staticX.......................
17. x.......................
18. staticX.......................
19. x.......................
20. staticX.......................
那当我们想让所有这个类下面的对象都同步的时候,也就是让所有这个类下面的对象共用同一把锁的时候,我们如何办呢?
看代码:
[java] view plaincopy
1. package com.jack.zhang.chapter9.classlock;
2.
3.
4. /**
5. * @author Jack Zhang
6. * @version vb1.0
7. * @Email virgoboy2004@163.com
8. * @Date 2012-5-20
9. */
10. public class Test
11. {
12. public final static Byte[] locks = new Byte[0];
13.
14. public static void staticX() throws InterruptedException
15. {
16. synchronized (locks)
17. {
18. for (int i = 0; i < 10; i++)
19. {
20. Thread.sleep(1000);
21. System.out.println("staticX.......................");
22. }
23. }
24. }
25.
26. public void x() throws InterruptedException
27. {
28. synchronized (locks)
29. {
30. for (int i = 0; i < 10; i++)
31. {
32. Thread.sleep(1000);
33. System.out.println("x.......................");
34. }
35. }
36. }
37.
38. public static void main(String[] args)
39. {
40. final Test test1 = new Test();
41. final Test test2 = new Test();
42. Thread thread = new Thread(new Runnable()
43. {
44. public void run()
45. {
46. try
47. {
48. test1.x();
49. }
50. catch (InterruptedException e)
51. {
52. // TODO Auto-generated catch block
53. e.printStackTrace();
54. }
55. }
56. }, "a");
随着学习的增多,以及对相关的数据结构和算法的实现,发现很多简单的数据结构和输入输出程序最好是使用自己的版本。比如每次使用下面的代码肯定是不可避免的
for(list::iterator i=li.begin();i!=li.end();i++)
cout<<*i<<" ";
cout<<endl;
上面的代码是不是很麻烦呢?你是否想过这样使用自己的测试代码呢?
list_ li;
li.print_list();
那就自己写一些简单的io,list库存放起来吧,每次都使用自己的,既熟悉又方便。
当然,自己的代码只有管理妥当了才会使用方便。这里主要包括:头文件的命名、头文件目录的放置、文件内部类的设计等。
第一,头文件的放置:你可能希望有一个自己的math.h,然后在项目中使用#include"math.h"或者#include<math.h>,但是糟糕的事情要发生了编译器有可能出现:
1>c:\program files\microsoft visual studio 9.0\vc\include\cmath(21) : error C2039: “acosf”: 不是“`global namespace'”的成员
1>c:\program files\microsoft visual studio 9.0\vc\include\cmath(21) : error C2873: “acosf”: 符号不能用在 using 声明中
1>c:\program files\microsoft visual studio 9.0\vc\include\cmath(21) : error C2039: “asinf”: 不是“`global namespace'”的成员
等。
这是因为你的math.h与系统库中的math.h冲突了。怎么办呢?你见过boost库中的包含方法吗?boost库中是这么做的:
#include<boost/random.hpp>
也就是说,他将random.hpp文件放在文件夹中,编译器找到的是这个文件夹boost的上层目录(注意不是boost目录本身,否则你就要使用#include<random.hpp>了),让后#include里就有boost了,就不会和其他文件夹中的random.hpp冲突了。你应该知道怎么创建自己的math.h了吧?是的,把自己经常使用的源文件放在目录中,将这个目录的父目录添加到编译器的附加目录中即可。
做法:右键项目名》属性》配置属性》c/c++》常规》附加包含目录,添加自己的库目录的父目录进来。
第二,头文件与源文件:一般的C++书都告诉我们,将声明放在头文件中(显示有哪些功能);将定义放在源文件中(功能的实现部分);头文件应该包含对应的源文件;使用时只需要包含对应的头文件即可。这都建立在上一步中添加附加目录已经设置的情况下。
import java.util.*; public class showCalendar{ //用来显示日历头 static final String head[] ={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"}; public static void main(String[] args) { Scanner in = new Scanner(System.in); int i; System.out.print("请输入年份:"); int year = in.nextInt(); System.out.print("请输入月份:"); int month = in.nextInt() - 1; //GregorianCalendar的第一个月是0,和人的理解不同 in.close(); //以指定的年、月、该月的第一天来创建对象 GregorianCalendar cal = new GregorianCalendar(year,month,1); //获取这个月的天数 int totalDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH); //获取这个月的第一天是星期几 int startDay = cal.get(Calendar.DAY_OF_WEEK)-1; //输出日历头部,每一个输出项占8个字符宽度 for(i=0; i<head.length; i++) System.out.print(head[i]+" "); System.out.println(); //输出第一天之前的空格 for(i=0;i<startDay;i++) System.out.print(" "); //依次输出每一天,每一个输出项占8个字符宽度 for(int day=1; day<=totalDays;day++){ System.out.printf(" %2d ",day); i++; if (i==7){ //每个星期输出完,换行 System.out.println(); i=0; } } } }