레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시

2019년 3월 8일 금요일

동기화 예제 - synchronized

- 자바 동기화(synchronized) 기본 예


1. 문제가 되는 코드
- 기본 코드
public class SimpleSynchronized {

int balance = 100000000;
int count1 = 0;
int count2 = 0;

public int getBalance() {
return balance;
}

public void addBalance(int balance) {
this.balance += balance;
}

public static void main(String[] args) {
final SimpleSynchronized simpleSynchronized = new SimpleSynchronized();
new Thread() {

@Override
public void run() {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count1++;
}

System.out.println("Thread 1 : " + simpleSynchronized.count1);
}

}.start();

new Thread() {

@Override
public void run() {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count2++;
}
System.out.println("Thread 2 : " + simpleSynchronized.count2);
}

}.start();

new Thread() {

@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("balance : " + simpleSynchronized.balance);
System.out.println("count total : " + (simpleSynchronized.count1 + simpleSynchronized.count2));
}

}.start();
}
}

- 결과
Thread 2 : 13312
Thread 1 : 89300
balance : -1000
count total : 102612

> 쓰레드1과 쓰레드2가 동일한 시간에 balance 값이 1000 보다 큰 경우만 -1000을 하면 결과적으로 1000 > 0 > -1000이 되는 문제가 발생한다.
> 루프 카운트도 100000000 / 1000 번을 하는 것이 아닌 것이 확인된다.


2. synchronized 적용
- 기본코드
public class SimpleSynchronized {

int balance = 100000000;
int count1 = 0;
int count2 = 0;

public int getBalance() {
return balance;
}

public void addBalance(int balance) {
this.balance += balance;
}

public static void main(String[] args) {
final SimpleSynchronized simpleSynchronized = new SimpleSynchronized();
new Thread() {

@Override
public void run() {
synchronized (simpleSynchronized) {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count1++;
}
}
System.out.println("Thread 1 : " + simpleSynchronized.count1);
}

}.start();

new Thread() {

@Override
public void run() {
synchronized (simpleSynchronized) {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count2++;
}
System.out.println("Thread 2 : " + simpleSynchronized.count2);
}
}

}.start();

new Thread() {

@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("balance : " + simpleSynchronized.balance);
System.out.println("count total : " + (simpleSynchronized.count1 + simpleSynchronized.count2));
}

}.start();
}
}

- 결과
Thread 2 : 0
Thread 1 : 100000
balance : 0
count total : 100000

> 쓰레드2는 쓰레드1이 simpleSynchronized 객체를 동기화 하기 때문에 쓰레드1의 작업이 완료되기 전까지 대기 한다.
> synchronized는 동기가 필요한 곳에 적절하게 적용해야 한다.
> 주된 예로 다중쓰레드 환경에서 Map 객체의 put과 remove를 synchronized없이 처리하면 문제가 되는 경우가 있다.





3. 동기화 기본 문법
- 객체 동기화
Object object = new Object();
synchronized (object) {

}

synchronized (this) {

}

> 기본변수(int, long, double 등) 타입은 적용 불가.

- 클래스 단위의 동기화
synchronized (Object.class) {

}

- 메소드 동기화
public synchronized void setObject(Object object) {

}

Restful API 예제코드 - HttpURLConnection

1. Restful API - HttpURLConnection
- 기본코드
String urlStr = "https://www.instagram.com/web/search/topsearch/?context=blended&query=java";
URL url = null;
HttpURLConnection connection = null;
BufferedReader reader = null;

try {
url = new URL(urlStr);
connection = urlStr.startsWith("https://") ? (HttpsURLConnection) url.openConnection() : (HttpURLConnection) url.openConnection();

connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
connection.setRequestProperty("cache-control", "no-cache");

connection.connect();

int code = connection.getResponseCode();
String message = connection.getResponseMessage();

StringBuffer buffer = null;
if (code == HttpURLConnection.HTTP_OK) {
buffer = new StringBuffer();

reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String temp = null;
while ((temp = reader.readLine()) != null) {
buffer.append(temp);
}

reader.close();
}
connection.disconnect();

System.out.println(String.format("Response : %d, %s", code, message));
System.out.println("Response DATA : ");
System.out.println(buffer == null ? "NULL " : buffer.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


- 결과
Response : 200, OK
Response DATA :
{}


> URL 문자열에서 HTTPS를 판단해서 캐스팅 할 클래스를 선택
> Restful API 사양에 맞는 RequestHeader 설정
> 예제코드에서 사용한 Restful API 주소는 인스타그램 검색 API

2019년 3월 5일 화요일

외부 프로세스 실행하기 - 자바


1. 프로세스 실행 - Process
- 메모장 실행 코드
try {
String command = "notepad";
Process process = Runtime.getRuntime().exec(command);
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}


- 결과
메모장 프로세스가 호출되면 process.waitFor(); 메소드에서 대기.
메모장 프로세스가 종료되면 process.destroy(); 메소드를 호출하고 종료.




2. 프로세스 출력 가져오기
- 실행코드
try {
String command = "cmd";
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "949"));

String temp = null;
while ((temp = reader.readLine()) != null) {
System.out.println(temp);

}
reader.close();
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}

- 결과
cmd는 출력 후 종료되는 방식이 아니므로 process.waitFor(); 메소드에서 대기.
keytool 실행 프로세스를 이용해서 테스트 해보면 process.destroy(); 까지 정상적으로 실행됩니다.

Hex.decodeHex - 바이트문자열 변환

- Hex.decodeHex를 통한 byteString을 정수형으로 변환하는 샘플.



1. 기본 예제
String value = "ff";

try {
byte[] bytes = Hex.decodeHex(value);
long result = bytes[0] & 0xff;

System.out.println(result);
} catch (DecoderException e) {
e.printStackTrace();
}

> 결과 : 255
> 0xff 마스크를 적용하지 않으면 -1 결과가 나옴.
> 2의 보수 위키백과 :
https://ko.wikipedia.org/wiki/2%EC%9D%98_%EB%B3%B4%EC%88%98







2. 변환 응용
- long 데이터로 변환 예제
String value = "FF7FFFFFFF";

try {
byte[] bytes = Hex.decodeHex(value);
long result = 0;

for (int i = bytes.length - 1; i >= 0; i--) {
result += (long) (bytes[i] & 0xff) << 8 * i;

}

System.out.println(result);
} catch (DecoderException e) {
e.printStackTrace();
}

> 결과 : 1099511595007
> int형 양수 최대 길이는 7FFFFFFF

String.format 예제 - 자바

- 자바 기준 예제
- 자주 사용하는 예제



1. 기본
- int, long
long value = 123456789;
System.out.println(String.format("%d", value));

System.out.println(String.format("%20d", value));
> 길이지정 결과 출력


- float, double
double value = 12345.6789;
System.out.println(String.format("%f", value));


- 문자열
String value = "ABC";
String value2 = "가나다";
System.out.println(String.format("%s, %s", value, value2));

System.out.println(String.format("%5s, %5s", value, value2));
> 길이지정 결과 출력




- Object
List<Object> list = new ArrayList<>();
list.add("ABC"); list.add(123);
list.add(456.789);

System.out.println(String.format("%s", list));
> toString()이 구현된 형태로 출력


- 배열
Arrays.asList을 이용
System.out.println(String.format("%s", Arrays.asList(new String[] { "123", "가나다" })));


- byte
int value = 65535;
System.out.println(String.format("%x", value));
System.out.println(String.format("%X", value));
System.out.println(String.format("%02X", value));





2. 자리수
- 콤마
double value = 12345.6789;
System.out.println(String.format("%,f", value));
System.out.println(String.format("%,d", (int)value));
> 정수는 d, 소수는 f로 적용


- 소수점 자르기(소수점 표현 지정)
double value = 12345.6789;
System.out.println(String.format("%.6f", value));
> 비는 소수점 자리는 0으로 채움







2016년 11월 12일 토요일

자바 String 기본 예제 - 문자열 다루기

1. 문자열 포함 - contains
System.out.println("ABCD123".contains("CD"));



2. 시작문자열 - startsWith
System.out.println("https://www.google.com".startsWith("https://"));



3. 끝 문자열 - endsWith
System.out.println("image.jpg".endsWith(".jpg"));



4. 비교 - equals, equalsIgnoreCase
- 대소문자 구분
System.out.println("image.jpg".equals("image.jpg"));

- 대소문자 무시
System.out.println("image.jpg".equalsIgnoreCase("IMAGE.jpg"));



5. 문자열 자르기 - substring
- index 부터 자르기
System.out.println("www.google.com".substring(3));
> 결과 : google.com

- 구간 자르기
System.out.println("www.google.com".substring(4, 10));
> 결과 : google



6. 문자열 위치 찾기 - indexOf, lastIndexOf
- 왼쪽 기준에서 위치 찾기
System.out.println("www.google.com".indexOf("google"));

- 오른쪽 기준에서 위치 찾기
System.out.println("www.google.com".lastIndexOf(".com"));


예) 구간 자르기와 함께 쓰기
String value = "www.google.com";
int beginIndex = value.indexOf(".") + 1;
int endIndex = value.lastIndexOf(".");
System.out.println(value.substring(beginIndex, endIndex));

> 결과 : google
> +1을 하는 이유 : 10 11 12 13 m



7. 정규식 - matches
- 특정 문자가 포함되는 여부 판단
System.out.println("Qwer123".matches(".*[a-z][A-Z].*"));
> 대소문자 포함 여부 확인



8. 문자열 분리(배열) - split
System.out.println(Arrays.asList("www.google.com".split("\\.")));
> 결과 : [www, google, com]



9. 문자열 바꾸기 - replace, replaceAll
- 바꾸기
System.out.println("www.google.com".replace("www", "https://www"));

- 모두 바꾸기
System.out.println("w w w . g o o g l e . c o m".replaceAll(" ", ""));
> 공백 모두 제거



10. 대소문자 변경 - toLowerCase, toUpperCase
- 모두 소문자
System.out.println("www.google.com".toLowerCase());

- 모두 대문자
System.out.println("www.google.com".toUpperCase());